惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

AWS News Blog
AWS News Blog
T
Tenable Blog
Project Zero
Project Zero
T
The Exploit Database - CXSecurity.com
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
T
Threatpost
Security Latest
Security Latest
C
Cisco Blogs
L
Lohrmann on Cybersecurity
S
Security @ Cisco Blogs
Google Online Security Blog
Google Online Security Blog
NISL@THU
NISL@THU
AI
AI
V
Vulnerabilities – Threatpost
Google DeepMind News
Google DeepMind News
C
Cyber Attacks, Cyber Crime and Cyber Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Last Watchdog
The Last Watchdog
G
GRAHAM CLULEY
Cloudbric
Cloudbric
H
Hackread – Cybersecurity News, Data Breaches, AI and More
H
Hacker News: Front Page
U
Unit 42
A
Arctic Wolf
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
MyScale Blog
MyScale Blog
O
OpenAI News
Scott Helme
Scott Helme
V2EX - 技术
V2EX - 技术
P
Proofpoint News Feed
博客园 - 叶小钗
Hugging Face - Blog
Hugging Face - Blog
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Cyberwarzone
Cyberwarzone
博客园 - 【当耐特】
H
Heimdal Security Blog
S
Schneier on Security
阮一峰的网络日志
阮一峰的网络日志
Help Net Security
Help Net Security
D
DataBreaches.Net
Y
Y Combinator Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
TaoSecurity Blog
TaoSecurity Blog
K
Kaspersky official blog
N
News and Events Feed by Topic
WordPress大学
WordPress大学
P
Palo Alto Networks Blog

爱吃肉的猫

那就,再相逢 Butterfly的魔改教程:最新评论页 离歌不夜天 前端分享 - 滑动阻尼效果 音乐分享 - doi微醺氛围 Butterfly的魔改教程:动态相册页 近况记事 - 11 微信公众号:Ai大模型让回复更具智能化 近况记事 - 10 PWA:让你的网站变成桌面应用APP Healthy Love Butterfly的魔改教程:关于本站 近况记事 - 9 Butterfly的魔改教程:待办清单 TrollStore - 不掉签助手 近况记事 - 8 Twikoo评论回复邮件模版 过一个很特别的七夕 The Young Boy and the Sea
Butterfly的魔改教程:右键菜单
亦小封 · 2024-04-01 · via 爱吃肉的猫
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
.js-pjax
#rightMenu
.rightMenu-group.rightMenu-small
.rightMenu-item#menu-backward
i.MeuiCat.icon-arrow-left-line
.rightMenu-item#menu-forward
i.MeuiCat.icon-arrow-right-line
.rightMenu-item#menu-refresh
i.MeuiCat.icon-restart-line
.rightMenu-item#menu-top
i.MeuiCat.icon-arrow-up-line
.rightMenu-group.rightMenuPost
if theme.readmode
.rightMenu-item#menu-reading
i.MeuiCat.icon-read-fill
span= '阅读模式'
//- .rightMenu-item#menu-commentBarrage
//- i.MeuiCat.icon-chat-fill
//- span= '评论弹窗'
.rightMenu-item#menu-postlink
i.MeuiCat.icon-external-link-fill
span= '分享本文'
.rightMenu-group.rightMenuPlugin
if theme.comments.use
.rightMenu-item#menu-commenttext
i.MeuiCat.icon-chat-new-fill
span= '引用评论'
.rightMenu-item#menu-copytext
i.MeuiCat.icon-copy-fill
span= '复制内容'
.rightMenu-item#menu-pastetext
i.MeuiCat.icon-clipboard-fill
span= '粘贴内容'
//- if theme.search.use
//- .rightMenu-item#menu-search
//- i.MeuiCat.icon-search-line
//- span= '站内搜索'
.rightMenu-item#menu-searchBaidu
i.MeuiCat.icon-baidu-fill
span= '百度搜索'
.rightMenu-item#menu-newwindow
i.MeuiCat.icon-window-fill
span= '新建窗口打开'
.rightMenu-item#menu-copylink
i.MeuiCat.icon-link-m-line
span= '复制链接地址'
.rightMenu-item#menu-copyimg
i.MeuiCat.icon-copy-fill
span= '复制此图片'
.rightMenu-item#menu-downloadimg
i.MeuiCat.icon-download-cloud-fill
span= '下载此图片'
.rightMenu-group.rightMenuOther
//- a.rightMenu-item#menu-randomPost
//- i.MeuiCat.icon-dice-fill
//- span= '随便逛逛'
if theme.darkmode.enable
.rightMenu-item#menu-darkmode
i.MeuiCat.icon-moon-clear-fill
span= '显示模式'
if theme.translate.enable
a.rightMenu-item#menu-translate
i.MeuiCat.icon-panben-line
span= '繁简转换'
.rightMenu-item#menu-asidehide
i.MeuiCat.icon-side-bar-fill
span= '边栏控制'
.rightMenu-group
a.rightMenu-item(href="/privacy/")
i.MeuiCat.icon-shield-user-fill
span= '隐私协议'
a.rightMenu-item(href="/cc/")
i.MeuiCat.icon-creative-commons-fill
span= '版权协议'
#rightMenu-mask
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293






class RightMenu {
constructor() {
this.selectTextNow = ""
this.domhref = ""
this.domImgSrc = ""
this.globalEvent = null
this.downloadimging = false
this.rmWidth = 0
this.rmHeight = 0
this.toLocal = btf.saveToLocal.get('rightside-status')
this.isEnabled = !this.toLocal || this.toLocal !== 'off' ? true : false
this.initialize()
window.rightMenu = undefined
}

initialize() {
window.addEventListener('load', () => {
this.addRightMenuClickEvent()
document.onmouseup = document.ondbclick = this.selceText.bind(this)
btf.addGlobalFn('pjaxComplete', () => { this.addRightMenuClickEvent() }, 'addRightMenuClickEvent')
})

window.oncontextmenu = (e) => this.onContextMenu(e)
}

enable() {
this.isEnabled = true
typeof !window.rightMenu && (window.rightMenu = {
getSelectTextNow: () => rightMenu.getSelectTextNow()
})
}

disable() {
this.isEnabled = false
typeof window.rightMenu && (window.rightMenu = undefined)
}

addRightMenuClickEvent() {
const menuItems = {
"rightMenu-mask": [this.hideRightMenu.bind(this)],
"menu-backward": [() => { window.history.back(); this.hideRightMenu() }],
"menu-forward": [() => { window.history.forward(); this.hideRightMenu() }],
"menu-refresh": [() => { this.hideRightMenu(); window.location.reload() }],
"menu-top": [() => { this.hideRightMenu(); btf.scrollToDest(0, 500) }],
"menu-darkmode": [() => { this.hideRightMenu(); document.querySelector('#darkmode').click() }],
"menu-translate": [() => { this.hideRightMenu(); typeof rightSideFn === 'object' && rightSideFn.translateLink() }],
"menu-reading": [() => { this.hideRightMenu(); document.querySelector('#readmode').click() }],
"menu-postlink": [this.copyPostUrl.bind(this)],
"menu-search": [this.hideRightMenu.bind(this)],
"menu-asidehide": [() => { this.hideRightMenu(); document.querySelector('#hide-aside-btn').click() }],
"menu-copytext": [() => { this.rightmenuCopyText(this.selectTextNow); GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow("复制成功,复制和转载请标注本文地址") }],
"menu-commenttext": [() => { commentText(this.selectTextNow); this.hideRightMenu() }],
"menu-searchBaidu": [this.searchBaidu.bind(this)],
"menu-newwindow": [() => { window.open(this.domhref); this.hideRightMenu() }],
"menu-copylink": [() => { this.rightmenuCopyText(this.domhref); GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow("已复制链接地址") }],
"menu-pastetext": [this.pasteText.bind(this)],
"menu-copylinkimg": [() => { this.rightmenuCopyText(this.domImgSrc); GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow("已复制图片链接") }],
"menu-copyimg": [() => { this.copyImage(this.domImgSrc) }],
"menu-downloadimg": [() => { this.downloadImage(this.domImgSrc, "MeuiCat") }],
"menu-commentBarrage": [() => { this.hideRightMenu(); typeof comment === 'object' && comment.closeBarrage() }],
"menu-randomPost": [() => { this.hideRightMenu(); toRandomPost() }]
}

for (let id in menuItems) {
const element = document.getElementById(id)
if (element) menuItems[id].forEach(fn => { element.addEventListener("click", fn) })
}

document.getElementById("rightMenu-mask").addEventListener("contextmenu", () => {
this.hideRightMenu()
return false
})
}

reloadrmSize() {
const menu = document.getElementById("rightMenu")
this.rmWidth = menu.offsetWidth
this.rmHeight = menu.offsetHeight
}

showRightMenu(more, mouseY = 0, mouseX = 0) {
const rightMenu = document.getElementById("rightMenu")

if (more) {
rightMenu.style.display = "block"
this.reloadrmSize()

mouseX + this.rmWidth + 20 > window.innerWidth && (mouseX -= this.rmWidth + 20)
mouseY + this.rmHeight > window.innerHeight && (mouseY -= mouseY + this.rmHeight - window.innerHeight + 20)
rightMenu.style.top = mouseY + "px"
rightMenu.style.left = mouseX + "px"

document.getElementById("rightMenu-mask").style.display = "flex"
this.stopMaskScroll()
} else {
rightMenu.style.display = "none"
}
}

hideRightMenu() {
this.showRightMenu(false)
document.getElementById("rightMenu-mask").style.display = "none"
}

getSelectTextNow() {
return this.selectTextNow
}

stopMaskScroll() {
const elements = ["rightMenu-mask", "rightMenu"]
elements.forEach(id => {
const element = document.getElementById(id)
if (element) element.addEventListener("mousewheel", this.hideRightMenu.bind(this), false)
})
}

selceText() {
this.selectTextNow = window.getSelection ? window.getSelection().toString() : document.selection ? document.selection.createRange().text : ""
}

copyPostUrl() {
this.copyUrl(window.location.href)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow("复制本页链接地址成功", false, 2000)
this.hideRightMenu()
}

searchBaidu() {
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow("即将跳转到百度搜索", false, 2000)
setTimeout(() => { window.open("https://www.baidu.com/s?wd=" + this.selectTextNow) }, 2000)
this.hideRightMenu()
}

pasteText() {
if (navigator.clipboard) navigator.clipboard.readText().then((text) => this.insertAtCaret(this.globalEvent.target, text))
this.hideRightMenu()
}

insertAtCaret(input, text) {
const start = input.selectionStart
const end = input.selectionEnd
if (document.selection) {
input.focus()
document.selection.createRange().text = text
input.focus()
} else if (start || start === 0) {
const scrollTop = input.scrollTop
input.value = input.value.substring(0, start) + text + input.value.substring(end, input.value.length)
input.focus()
input.selectionStart = start + text.length
input.selectionEnd = start + text.length
input.scrollTop = scrollTop
} else {
input.value += text
input.focus()
}
}

rightmenuCopyText(text) {
if (navigator.clipboard) navigator.clipboard.writeText(text)
this.hideRightMenu()
}

imageToBlob(imgSrc, options = {}) {
const { fileName, action = "download", callback } = options
const canvas = document.createElement("canvas")
const context = canvas.getContext("2d")
const img = new Image()

img.crossOrigin = 'anonymous'
img.src = imgSrc

return new Promise((resolve, reject) => {
img.onload = function () {
canvas.width = img.width
canvas.height = img.height
context.drawImage(this, 0, 0)

if (action === 'copy') {
canvas.toBlob((blob) => {
const item = new ClipboardItem({ "image/png": blob })
navigator.clipboard.write([item]).then(() => {
callback && callback("复制成功!图片已添加盲水印,请遵守版权协议")
resolve()
})
}, "image/png", 0.75)
} else if (action === 'download') {
const dataURL = canvas.toDataURL("image/png")
const a = document.createElement("a")
const event = new MouseEvent("click")
a.download = fileName || "image.png"
a.href = dataURL
a.dispatchEvent(event)
callback && callback("图片已添加盲水印,请遵守版权协议")
resolve()
}
}

img.onerror = () => {
callback && callback("图片加载失败,请检查跨域或网络连接")
reject(new Error("Image load error"))
}
})
}

copyImage(imgSrc) {
this.hideRightMenu()
const time = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1" ? 0 : 5000
if (this.downloadimging) return GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow("有正在进行中的任务,请稍后再试", false, time)
this.downloadimging = true

setTimeout(() => {
this.imageToBlob(imgSrc, {
action: "copy",
callback: (msg) => {
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(msg)
this.downloadimging = false
}
})
}, time)
}

downloadImage(imgSrc, fileName) {
this.hideRightMenu()
if (this.downloadimging) return GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow("有正在进行中的下载,请稍后再试")
this.downloadimging = true
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow("正在下载中,请稍后", false, 10000)

setTimeout(() => {
this.imageToBlob(imgSrc, {
action: "download",
fileName: fileName,
callback: (msg) => {
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(msg)
this.downloadimging = false
}
})
}, 10000)
}

onContextMenu(e) {
if (this.isEnabled && document.body.clientWidth > 768) {
const mouseX = e.clientX + 12,
mouseY = e.clientY,
target = e.target,
menus = {
rightMenuPost: document.querySelector(".rightMenuPost"),
rightMenuPlugin: document.querySelector(".rightMenuPlugin"),
rightMenuOther: document.querySelector(".rightMenuOther"),
},
menuItems = {
menuCopyText: { element: document.getElementById("menu-copytext"), condition: () => this.selectTextNow && window.getSelection },
menuCommentText: { element: document.getElementById("menu-commenttext"), condition: () => this.selectTextNow && document.getElementById("post-comment") },
menuSearch: { element: document.getElementById("menu-search"), condition: () => this.selectTextNow },
menuSearchBaidu: { element: document.getElementById("menu-searchBaidu"), condition: () => this.selectTextNow },
menuNewWindow: { element: document.getElementById("menu-newwindow"), condition: () => !!target.href },
menuCopyLink: { element: document.getElementById("menu-copylink"), condition: () => !!target.href },
menuCopyImage: { element: document.getElementById("menu-copyimg"), condition: () => !!target.currentSrc },
menuDownloadImage: { element: document.getElementById("menu-downloadimg"), condition: () => !!target.currentSrc },
menuPasteText: { element: document.getElementById("menu-pastetext"), condition: () => ["input", "textarea"].includes(target.tagName.toLowerCase()) },
}

this.domhref = target.href || ""
this.domImgSrc = target.src || ""

Object.values(menuItems).forEach(({ element, condition }) => { if (element) element.style.display = condition() ? "block" : "none" })

const isTextSelected = Object.values(menuItems).some(({ condition }) => condition())
menus.rightMenuPost.style.display = isTextSelected || !!target.href || !!target.currentSrc ? "none" : document.querySelector("#body-wrap.post") ? "block" : "none"
menus.rightMenuPlugin.style.display = isTextSelected ? "block" : "none"
menus.rightMenuOther.style.display = isTextSelected ? "none" : "block"

const isReadMode = document.querySelector(".read-mode");
["menu-commentBarrage", "menu-postlink", "menu-randomPost", "menu-asidehide"].forEach((id) => {
const element = document.getElementById(id)
if (element) element.style.display = isReadMode ? "none" : "block"
})

this.showRightMenu(e, mouseY, mouseX)
e.preventDefault()
return false
} else {
return true
}
}
}

const rightMenu = new RightMenu()

复制图片下载图片 这两个功能都需要浏览器支持ClipboardItemAPI,并且图片服务器正确设置CORS跨域。
如遇错误提示,大概率就是涉及到跨域问题。自行设置解决。