poi-plugin-reload-game-button 0.3.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/README.md +31 -0
- package/i18n/en-US.json +10 -0
- package/i18n/zh-CN.json +10 -0
- package/index.js +454 -0
- package/package.json +40 -0
- package/views/index.js +107 -0
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# poi-plugin-reload-game-button
|
|
2
|
+
|
|
3
|
+
## 中文
|
|
4
|
+
|
|
5
|
+
适用于 poi 的触摸友好悬浮按钮插件,用来只重新载入游戏本体。
|
|
6
|
+
|
|
7
|
+
这个按钮调用 poi 现有的 `gameReload()` 逻辑。如果该逻辑无法加载,会回退到与 poi 相同的
|
|
8
|
+
webview JavaScript 重新载入方式。
|
|
9
|
+
|
|
10
|
+
悬浮窗默认显示在窗口右侧。拖动顶部标题栏可以移动,拖动右下角可以调整大小,位置和尺寸会
|
|
11
|
+
保存到 `localStorage`。
|
|
12
|
+
|
|
13
|
+
点击悬浮窗右上角关闭按钮可以隐藏它。隐藏后,在 poi 的插件主页打开本插件,点击“显示悬浮窗”
|
|
14
|
+
即可重新打开。
|
|
15
|
+
|
|
16
|
+
仓库地址:https://github.com/DuskWhite/poi-plugin-reload-game-button
|
|
17
|
+
|
|
18
|
+
## English
|
|
19
|
+
|
|
20
|
+
A touch-friendly floating panel plugin for poi that reloads only the game frame.
|
|
21
|
+
|
|
22
|
+
The button calls poi's existing `gameReload()` helper. If that helper cannot be loaded, it falls back
|
|
23
|
+
to the same webview JavaScript used by poi.
|
|
24
|
+
|
|
25
|
+
The panel starts on the right side of the window. Drag the top handle to move it, and drag the
|
|
26
|
+
bottom-right corner to resize it. Position and size are saved in `localStorage`.
|
|
27
|
+
|
|
28
|
+
Use the close button in the panel header to hide it. Open the plugin page from poi's plugin list and
|
|
29
|
+
click "Show floating panel" to bring it back.
|
|
30
|
+
|
|
31
|
+
Repository: https://github.com/DuskWhite/poi-plugin-reload-game-button
|
package/i18n/en-US.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Reload Game Button",
|
|
3
|
+
"description": "A touch-friendly floating button for reloading only the game frame.",
|
|
4
|
+
"showPanel": "Show floating panel",
|
|
5
|
+
"reloadGame": "Reload game",
|
|
6
|
+
"repository": "Repository",
|
|
7
|
+
"panelVisible": "Floating panel is visible.",
|
|
8
|
+
"panelHidden": "Floating panel is hidden.",
|
|
9
|
+
"close": "Close"
|
|
10
|
+
}
|
package/i18n/zh-CN.json
ADDED
package/index.js
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const PLUGIN_ID = 'poi-plugin-reload-game-button'
|
|
4
|
+
const PANEL_ID = 'poi-reload-game-panel'
|
|
5
|
+
const STYLE_ID = 'poi-reload-game-button-style'
|
|
6
|
+
const STORAGE_KEY = 'poi-plugin-reload-game-button:panel-state'
|
|
7
|
+
const CLOSED_STORAGE_KEY = 'poi-plugin-reload-game-button:panel-closed'
|
|
8
|
+
const SHOW_PANEL_EVENT = 'poi-plugin-reload-game-button:show-panel'
|
|
9
|
+
const RELOAD_GAME_EVENT = 'poi-plugin-reload-game-button:reload-game'
|
|
10
|
+
const RELOAD_TITLE = '重新载入游戏'
|
|
11
|
+
|
|
12
|
+
const DEFAULT_STATE = {
|
|
13
|
+
width: 168,
|
|
14
|
+
height: 78,
|
|
15
|
+
top: null,
|
|
16
|
+
left: null,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let observer = null
|
|
20
|
+
let retryTimer = null
|
|
21
|
+
|
|
22
|
+
function reloadGameFallback() {
|
|
23
|
+
const { getStore } = require('views/create-store')
|
|
24
|
+
getStore('layout.webview.ref')?.executeJavaScript(`
|
|
25
|
+
var doc;
|
|
26
|
+
if (document.getElementById('game_frame')) {
|
|
27
|
+
doc = document.getElementById('game_frame').contentDocument;
|
|
28
|
+
} else {
|
|
29
|
+
doc = document;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var game = doc.getElementById('htmlWrap');
|
|
33
|
+
if (game) {
|
|
34
|
+
game.contentWindow.location.reload()
|
|
35
|
+
}
|
|
36
|
+
`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function reloadGame() {
|
|
40
|
+
try {
|
|
41
|
+
const { gameReload } = require('views/services/utils')
|
|
42
|
+
gameReload()
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.warn(`${PLUGIN_ID}: falling back to inline reload`, error)
|
|
45
|
+
reloadGameFallback()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function readPanelState() {
|
|
50
|
+
try {
|
|
51
|
+
const raw = window.localStorage.getItem(STORAGE_KEY)
|
|
52
|
+
if (!raw) {
|
|
53
|
+
return { ...DEFAULT_STATE }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const parsed = JSON.parse(raw)
|
|
57
|
+
return {
|
|
58
|
+
width: Number.isFinite(parsed.width) ? parsed.width : DEFAULT_STATE.width,
|
|
59
|
+
height: Number.isFinite(parsed.height) ? parsed.height : DEFAULT_STATE.height,
|
|
60
|
+
top: Number.isFinite(parsed.top) ? parsed.top : DEFAULT_STATE.top,
|
|
61
|
+
left: Number.isFinite(parsed.left) ? parsed.left : DEFAULT_STATE.left,
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.warn(`${PLUGIN_ID}: failed to read panel state`, error)
|
|
65
|
+
return { ...DEFAULT_STATE }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function writePanelState(panel) {
|
|
70
|
+
const rect = panel.getBoundingClientRect()
|
|
71
|
+
const state = {
|
|
72
|
+
width: Math.round(rect.width),
|
|
73
|
+
height: Math.round(rect.height),
|
|
74
|
+
top: Math.round(rect.top),
|
|
75
|
+
left: Math.round(rect.left),
|
|
76
|
+
}
|
|
77
|
+
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(state))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isPanelClosed() {
|
|
81
|
+
return window.localStorage.getItem(CLOSED_STORAGE_KEY) === 'true'
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function setPanelClosed(closed) {
|
|
85
|
+
window.localStorage.setItem(CLOSED_STORAGE_KEY, closed ? 'true' : 'false')
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function clamp(value, min, max) {
|
|
89
|
+
return Math.min(Math.max(value, min), max)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function clampPanel(panel) {
|
|
93
|
+
const rect = panel.getBoundingClientRect()
|
|
94
|
+
const left = clamp(rect.left, 0, Math.max(0, window.innerWidth - rect.width))
|
|
95
|
+
const top = clamp(rect.top, 0, Math.max(0, window.innerHeight - rect.height))
|
|
96
|
+
panel.style.left = `${Math.round(left)}px`
|
|
97
|
+
panel.style.top = `${Math.round(top)}px`
|
|
98
|
+
panel.style.right = 'auto'
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function applyPanelState(panel) {
|
|
102
|
+
const state = readPanelState()
|
|
103
|
+
const width = clamp(state.width, 120, Math.max(120, window.innerWidth))
|
|
104
|
+
const height = clamp(state.height, 58, Math.max(58, window.innerHeight))
|
|
105
|
+
|
|
106
|
+
panel.style.width = `${Math.round(width)}px`
|
|
107
|
+
panel.style.height = `${Math.round(height)}px`
|
|
108
|
+
|
|
109
|
+
if (state.left == null || state.top == null) {
|
|
110
|
+
panel.style.right = '14px'
|
|
111
|
+
panel.style.left = 'auto'
|
|
112
|
+
panel.style.top = `${Math.round((window.innerHeight - height) / 2)}px`
|
|
113
|
+
} else {
|
|
114
|
+
panel.style.left = `${Math.round(state.left)}px`
|
|
115
|
+
panel.style.top = `${Math.round(state.top)}px`
|
|
116
|
+
panel.style.right = 'auto'
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
window.requestAnimationFrame(() => clampPanel(panel))
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function ensureStyle() {
|
|
123
|
+
if (document.getElementById(STYLE_ID)) {
|
|
124
|
+
return
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const style = document.createElement('style')
|
|
128
|
+
style.id = STYLE_ID
|
|
129
|
+
style.textContent = `
|
|
130
|
+
#${PANEL_ID} {
|
|
131
|
+
backdrop-filter: blur(12px);
|
|
132
|
+
background: rgba(35, 40, 48, 0.88);
|
|
133
|
+
border: 1px solid rgba(255, 255, 255, 0.18);
|
|
134
|
+
border-radius: 8px;
|
|
135
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
|
|
136
|
+
box-sizing: border-box;
|
|
137
|
+
color: #fff;
|
|
138
|
+
display: flex;
|
|
139
|
+
flex-direction: column;
|
|
140
|
+
min-height: 58px;
|
|
141
|
+
min-width: 120px;
|
|
142
|
+
overflow: hidden;
|
|
143
|
+
position: fixed;
|
|
144
|
+
z-index: 2147483000;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#${PANEL_ID} .poi-reload-game-panel-handle {
|
|
148
|
+
align-items: center;
|
|
149
|
+
background: rgba(255, 255, 255, 0.1);
|
|
150
|
+
cursor: move;
|
|
151
|
+
display: flex;
|
|
152
|
+
flex: 0 0 22px;
|
|
153
|
+
font-size: 11px;
|
|
154
|
+
font-weight: 600;
|
|
155
|
+
justify-content: center;
|
|
156
|
+
letter-spacing: 0;
|
|
157
|
+
line-height: 22px;
|
|
158
|
+
touch-action: none;
|
|
159
|
+
user-select: none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
#${PANEL_ID} .poi-reload-game-panel-title {
|
|
163
|
+
flex: 1 1 auto;
|
|
164
|
+
text-align: center;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
#${PANEL_ID} .poi-reload-game-panel-close {
|
|
168
|
+
align-items: center;
|
|
169
|
+
background: transparent;
|
|
170
|
+
border: 0;
|
|
171
|
+
color: rgba(255, 255, 255, 0.86);
|
|
172
|
+
cursor: pointer;
|
|
173
|
+
display: flex;
|
|
174
|
+
flex: 0 0 26px;
|
|
175
|
+
font-size: 17px;
|
|
176
|
+
height: 22px;
|
|
177
|
+
justify-content: center;
|
|
178
|
+
line-height: 1;
|
|
179
|
+
padding: 0;
|
|
180
|
+
touch-action: manipulation;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
#${PANEL_ID} .poi-reload-game-panel-close:active {
|
|
184
|
+
background: rgba(255, 255, 255, 0.12);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
#${PANEL_ID} .poi-reload-game-panel-button {
|
|
188
|
+
align-items: center;
|
|
189
|
+
background: #d9822b;
|
|
190
|
+
border: 0;
|
|
191
|
+
color: #fff;
|
|
192
|
+
cursor: pointer;
|
|
193
|
+
display: flex;
|
|
194
|
+
flex: 1 1 auto;
|
|
195
|
+
font-size: 18px;
|
|
196
|
+
font-weight: 700;
|
|
197
|
+
justify-content: center;
|
|
198
|
+
letter-spacing: 0;
|
|
199
|
+
line-height: 1.2;
|
|
200
|
+
min-height: 36px;
|
|
201
|
+
padding: 8px 12px;
|
|
202
|
+
text-align: center;
|
|
203
|
+
touch-action: manipulation;
|
|
204
|
+
user-select: none;
|
|
205
|
+
width: 100%;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
#${PANEL_ID} .poi-reload-game-panel-button:active {
|
|
209
|
+
background: #bf7326;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
#${PANEL_ID} .poi-reload-game-panel-resizer {
|
|
213
|
+
border-bottom: 12px solid rgba(255, 255, 255, 0.72);
|
|
214
|
+
border-left: 12px solid transparent;
|
|
215
|
+
bottom: 4px;
|
|
216
|
+
cursor: nwse-resize;
|
|
217
|
+
height: 0;
|
|
218
|
+
position: absolute;
|
|
219
|
+
right: 4px;
|
|
220
|
+
touch-action: none;
|
|
221
|
+
width: 0;
|
|
222
|
+
}
|
|
223
|
+
`
|
|
224
|
+
document.head.appendChild(style)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function createPanel() {
|
|
228
|
+
const panel = document.createElement('div')
|
|
229
|
+
panel.id = PANEL_ID
|
|
230
|
+
|
|
231
|
+
const handle = document.createElement('div')
|
|
232
|
+
handle.className = 'poi-reload-game-panel-handle'
|
|
233
|
+
|
|
234
|
+
const title = document.createElement('div')
|
|
235
|
+
title.className = 'poi-reload-game-panel-title'
|
|
236
|
+
title.textContent = 'Reload'
|
|
237
|
+
|
|
238
|
+
const close = document.createElement('button')
|
|
239
|
+
close.type = 'button'
|
|
240
|
+
close.className = 'poi-reload-game-panel-close'
|
|
241
|
+
close.title = '关闭'
|
|
242
|
+
close.setAttribute('aria-label', '关闭')
|
|
243
|
+
close.textContent = '×'
|
|
244
|
+
close.addEventListener('pointerdown', (event) => {
|
|
245
|
+
event.stopPropagation()
|
|
246
|
+
})
|
|
247
|
+
close.addEventListener('click', (event) => {
|
|
248
|
+
event.preventDefault()
|
|
249
|
+
event.stopPropagation()
|
|
250
|
+
closePanel(panel)
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
handle.appendChild(title)
|
|
254
|
+
handle.appendChild(close)
|
|
255
|
+
|
|
256
|
+
const button = document.createElement('button')
|
|
257
|
+
button.type = 'button'
|
|
258
|
+
button.className = 'poi-reload-game-panel-button'
|
|
259
|
+
button.title = RELOAD_TITLE
|
|
260
|
+
button.setAttribute('aria-label', RELOAD_TITLE)
|
|
261
|
+
button.textContent = RELOAD_TITLE
|
|
262
|
+
button.addEventListener('click', (event) => {
|
|
263
|
+
event.preventDefault()
|
|
264
|
+
event.stopPropagation()
|
|
265
|
+
reloadGame()
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
const resizer = document.createElement('div')
|
|
269
|
+
resizer.className = 'poi-reload-game-panel-resizer'
|
|
270
|
+
|
|
271
|
+
panel.appendChild(handle)
|
|
272
|
+
panel.appendChild(button)
|
|
273
|
+
panel.appendChild(resizer)
|
|
274
|
+
|
|
275
|
+
makePanelDraggable(panel, handle)
|
|
276
|
+
makePanelResizable(panel, resizer)
|
|
277
|
+
applyPanelState(panel)
|
|
278
|
+
|
|
279
|
+
return panel
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function closePanel(panel) {
|
|
283
|
+
writePanelState(panel)
|
|
284
|
+
setPanelClosed(true)
|
|
285
|
+
panel.remove()
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function makePanelDraggable(panel, handle) {
|
|
289
|
+
handle.addEventListener('pointerdown', (event) => {
|
|
290
|
+
event.preventDefault()
|
|
291
|
+
panel.setPointerCapture?.(event.pointerId)
|
|
292
|
+
|
|
293
|
+
const rect = panel.getBoundingClientRect()
|
|
294
|
+
const startX = event.clientX
|
|
295
|
+
const startY = event.clientY
|
|
296
|
+
const startLeft = rect.left
|
|
297
|
+
const startTop = rect.top
|
|
298
|
+
|
|
299
|
+
const onMove = (moveEvent) => {
|
|
300
|
+
const left = startLeft + moveEvent.clientX - startX
|
|
301
|
+
const top = startTop + moveEvent.clientY - startY
|
|
302
|
+
panel.style.left = `${Math.round(left)}px`
|
|
303
|
+
panel.style.top = `${Math.round(top)}px`
|
|
304
|
+
panel.style.right = 'auto'
|
|
305
|
+
clampPanel(panel)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const onEnd = () => {
|
|
309
|
+
window.removeEventListener('pointermove', onMove)
|
|
310
|
+
window.removeEventListener('pointerup', onEnd)
|
|
311
|
+
window.removeEventListener('pointercancel', onEnd)
|
|
312
|
+
writePanelState(panel)
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
window.addEventListener('pointermove', onMove)
|
|
316
|
+
window.addEventListener('pointerup', onEnd)
|
|
317
|
+
window.addEventListener('pointercancel', onEnd)
|
|
318
|
+
})
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function makePanelResizable(panel, resizer) {
|
|
322
|
+
resizer.addEventListener('pointerdown', (event) => {
|
|
323
|
+
event.preventDefault()
|
|
324
|
+
event.stopPropagation()
|
|
325
|
+
panel.setPointerCapture?.(event.pointerId)
|
|
326
|
+
|
|
327
|
+
const rect = panel.getBoundingClientRect()
|
|
328
|
+
const startX = event.clientX
|
|
329
|
+
const startY = event.clientY
|
|
330
|
+
const startWidth = rect.width
|
|
331
|
+
const startHeight = rect.height
|
|
332
|
+
|
|
333
|
+
const onMove = (moveEvent) => {
|
|
334
|
+
const width = clamp(startWidth + moveEvent.clientX - startX, 120, window.innerWidth)
|
|
335
|
+
const height = clamp(startHeight + moveEvent.clientY - startY, 58, window.innerHeight)
|
|
336
|
+
panel.style.width = `${Math.round(width)}px`
|
|
337
|
+
panel.style.height = `${Math.round(height)}px`
|
|
338
|
+
clampPanel(panel)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const onEnd = () => {
|
|
342
|
+
window.removeEventListener('pointermove', onMove)
|
|
343
|
+
window.removeEventListener('pointerup', onEnd)
|
|
344
|
+
window.removeEventListener('pointercancel', onEnd)
|
|
345
|
+
writePanelState(panel)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
window.addEventListener('pointermove', onMove)
|
|
349
|
+
window.addEventListener('pointerup', onEnd)
|
|
350
|
+
window.addEventListener('pointercancel', onEnd)
|
|
351
|
+
})
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function injectPanel() {
|
|
355
|
+
if (!document.body) {
|
|
356
|
+
return false
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (isPanelClosed()) {
|
|
360
|
+
return false
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (document.getElementById(PANEL_ID)) {
|
|
364
|
+
return true
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
ensureStyle()
|
|
368
|
+
document.body.appendChild(createPanel())
|
|
369
|
+
return true
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function showPanel() {
|
|
373
|
+
setPanelClosed(false)
|
|
374
|
+
injectPanel()
|
|
375
|
+
const panel = document.getElementById(PANEL_ID)
|
|
376
|
+
if (panel) {
|
|
377
|
+
clampPanel(panel)
|
|
378
|
+
writePanelState(panel)
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function startObserver() {
|
|
383
|
+
if (observer || !document.body) {
|
|
384
|
+
return
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
observer = new MutationObserver(() => {
|
|
388
|
+
injectPanel()
|
|
389
|
+
})
|
|
390
|
+
observer.observe(document.body, {
|
|
391
|
+
childList: true,
|
|
392
|
+
})
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function startRetryTimer() {
|
|
396
|
+
if (retryTimer) {
|
|
397
|
+
return
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
retryTimer = window.setInterval(() => {
|
|
401
|
+
if (injectPanel() && retryTimer) {
|
|
402
|
+
window.clearInterval(retryTimer)
|
|
403
|
+
retryTimer = null
|
|
404
|
+
}
|
|
405
|
+
startObserver()
|
|
406
|
+
}, 1000)
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function pluginDidLoad() {
|
|
410
|
+
if (document.readyState === 'loading') {
|
|
411
|
+
document.addEventListener('DOMContentLoaded', pluginDidLoad, { once: true })
|
|
412
|
+
return
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
injectPanel()
|
|
416
|
+
startObserver()
|
|
417
|
+
startRetryTimer()
|
|
418
|
+
window.addEventListener('resize', handleWindowResize)
|
|
419
|
+
window.addEventListener(SHOW_PANEL_EVENT, showPanel)
|
|
420
|
+
window.addEventListener(RELOAD_GAME_EVENT, reloadGame)
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function handleWindowResize() {
|
|
424
|
+
const panel = document.getElementById(PANEL_ID)
|
|
425
|
+
if (panel) {
|
|
426
|
+
clampPanel(panel)
|
|
427
|
+
writePanelState(panel)
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function pluginWillUnload() {
|
|
432
|
+
document.removeEventListener('DOMContentLoaded', pluginDidLoad)
|
|
433
|
+
window.removeEventListener('resize', handleWindowResize)
|
|
434
|
+
window.removeEventListener(SHOW_PANEL_EVENT, showPanel)
|
|
435
|
+
window.removeEventListener(RELOAD_GAME_EVENT, reloadGame)
|
|
436
|
+
document.getElementById(PANEL_ID)?.remove()
|
|
437
|
+
document.getElementById(STYLE_ID)?.remove()
|
|
438
|
+
|
|
439
|
+
if (observer) {
|
|
440
|
+
observer.disconnect()
|
|
441
|
+
observer = null
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (retryTimer) {
|
|
445
|
+
window.clearInterval(retryTimer)
|
|
446
|
+
retryTimer = null
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
module.exports = {
|
|
451
|
+
pluginDidLoad,
|
|
452
|
+
pluginWillUnload,
|
|
453
|
+
reactClass: (props) => require('./views').reactClass(props),
|
|
454
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "poi-plugin-reload-game-button",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Adds a touch-friendly floating reload-game panel to poi.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"README.md",
|
|
8
|
+
"index.js",
|
|
9
|
+
"views",
|
|
10
|
+
"i18n"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "node test.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"kancolle",
|
|
17
|
+
"poi",
|
|
18
|
+
"plugin",
|
|
19
|
+
"poi-plugin",
|
|
20
|
+
"reload",
|
|
21
|
+
"touch"
|
|
22
|
+
],
|
|
23
|
+
"author": "DuskWhite",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/DuskWhite/poi-plugin-reload-game-button.git"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/DuskWhite/poi-plugin-reload-game-button#readme",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/DuskWhite/poi-plugin-reload-game-button/issues"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"poiPlugin": {
|
|
34
|
+
"title": "重新载入游戏",
|
|
35
|
+
"description": "适合触摸屏使用的悬浮按钮,只重新载入游戏本体。",
|
|
36
|
+
"icon": "fa/refresh",
|
|
37
|
+
"priority": 10000,
|
|
38
|
+
"i18nDir": "i18n"
|
|
39
|
+
}
|
|
40
|
+
}
|
package/views/index.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const React = require('react')
|
|
4
|
+
const { Button, Callout, Intent } = require('@blueprintjs/core')
|
|
5
|
+
const { useTranslation } = require('react-i18next')
|
|
6
|
+
|
|
7
|
+
const SHOW_PANEL_EVENT = 'poi-plugin-reload-game-button:show-panel'
|
|
8
|
+
const RELOAD_GAME_EVENT = 'poi-plugin-reload-game-button:reload-game'
|
|
9
|
+
const PANEL_ID = 'poi-reload-game-panel'
|
|
10
|
+
const REPOSITORY_URL = 'https://github.com/DuskWhite/poi-plugin-reload-game-button'
|
|
11
|
+
|
|
12
|
+
function tt(t, key, fallback) {
|
|
13
|
+
const translated = t(key)
|
|
14
|
+
return translated === key ? fallback : translated
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function reactClass() {
|
|
18
|
+
const { t } = useTranslation('poi-plugin-reload-game-button')
|
|
19
|
+
const [visible, setVisible] = React.useState(() => Boolean(document.getElementById(PANEL_ID)))
|
|
20
|
+
|
|
21
|
+
React.useEffect(() => {
|
|
22
|
+
const updateVisible = () => setVisible(Boolean(document.getElementById(PANEL_ID)))
|
|
23
|
+
const timer = window.setInterval(updateVisible, 1000)
|
|
24
|
+
window.addEventListener(SHOW_PANEL_EVENT, updateVisible)
|
|
25
|
+
return () => {
|
|
26
|
+
window.clearInterval(timer)
|
|
27
|
+
window.removeEventListener(SHOW_PANEL_EVENT, updateVisible)
|
|
28
|
+
}
|
|
29
|
+
}, [])
|
|
30
|
+
|
|
31
|
+
const showPanel = () => {
|
|
32
|
+
window.dispatchEvent(new Event(SHOW_PANEL_EVENT))
|
|
33
|
+
window.setTimeout(() => setVisible(Boolean(document.getElementById(PANEL_ID))), 0)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const reloadGame = () => {
|
|
37
|
+
window.dispatchEvent(new Event(RELOAD_GAME_EVENT))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return React.createElement(
|
|
41
|
+
'div',
|
|
42
|
+
{ style: { padding: 12 } },
|
|
43
|
+
React.createElement(
|
|
44
|
+
Callout,
|
|
45
|
+
{
|
|
46
|
+
intent: Intent.PRIMARY,
|
|
47
|
+
title: tt(t, 'title', '重新载入游戏'),
|
|
48
|
+
},
|
|
49
|
+
tt(t, 'description', '适合触摸屏使用的悬浮按钮,只重新载入游戏本体。'),
|
|
50
|
+
),
|
|
51
|
+
React.createElement(
|
|
52
|
+
'div',
|
|
53
|
+
{
|
|
54
|
+
style: {
|
|
55
|
+
display: 'flex',
|
|
56
|
+
gap: 8,
|
|
57
|
+
marginTop: 12,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
React.createElement(
|
|
61
|
+
Button,
|
|
62
|
+
{
|
|
63
|
+
icon: 'widget',
|
|
64
|
+
intent: Intent.PRIMARY,
|
|
65
|
+
large: true,
|
|
66
|
+
onClick: showPanel,
|
|
67
|
+
},
|
|
68
|
+
tt(t, 'showPanel', '显示悬浮窗'),
|
|
69
|
+
),
|
|
70
|
+
React.createElement(
|
|
71
|
+
Button,
|
|
72
|
+
{
|
|
73
|
+
icon: 'refresh',
|
|
74
|
+
intent: Intent.WARNING,
|
|
75
|
+
large: true,
|
|
76
|
+
onClick: reloadGame,
|
|
77
|
+
},
|
|
78
|
+
tt(t, 'reloadGame', '重新载入游戏'),
|
|
79
|
+
),
|
|
80
|
+
),
|
|
81
|
+
React.createElement(
|
|
82
|
+
'div',
|
|
83
|
+
{ style: { marginTop: 10, opacity: 0.78 } },
|
|
84
|
+
visible
|
|
85
|
+
? tt(t, 'panelVisible', '悬浮窗已显示。')
|
|
86
|
+
: tt(t, 'panelHidden', '悬浮窗已隐藏。'),
|
|
87
|
+
),
|
|
88
|
+
React.createElement(
|
|
89
|
+
'div',
|
|
90
|
+
{ style: { marginTop: 10 } },
|
|
91
|
+
`${tt(t, 'repository', '仓库地址')}: `,
|
|
92
|
+
React.createElement(
|
|
93
|
+
'a',
|
|
94
|
+
{
|
|
95
|
+
href: REPOSITORY_URL,
|
|
96
|
+
onClick: (event) => {
|
|
97
|
+
event.preventDefault()
|
|
98
|
+
require('electron').shell.openExternal(REPOSITORY_URL)
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
REPOSITORY_URL,
|
|
102
|
+
),
|
|
103
|
+
),
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
exports.reactClass = reactClass
|