修改PUG

新建 [blogRoot]\themes\butterfly\layout\includes\rightmenu.pug

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
#rightMenu.js-pjax
.rightMenu-group.rightMenu-small
a.rightMenu-item(href="javascript:window.history.back();")
i.fa.fa-arrow-left
a.rightMenu-item(href="javascript:window.history.forward();")
i.fa.fa-arrow-right
a.rightMenu-item(href="javascript:window.location.reload();")
i.fa.fa-refresh
a.rightMenu-item(href="javascript:rmf.scrollToTop();")
i.fa.fa-arrow-up
.rightMenu-group.rightMenu-line.hide#menu-text
a.rightMenu-item(href="javascript:rmf.copySelect();")
i.fa.fa-copy
span='复制'
a.rightMenu-item(href="javascript:window.open(\"https://www.baidu.com/s?wd=\"+window.getSelection().toString());window.location.reload();")
i.iconfont.icon-baidu
span='百度搜索'
//a.rightMenu-item(href="javascript:rmf.searchinThisPage();")
// i.fas.fa-search
// span='站内搜索'
a.rightMenu-item(href="#post-comment" onclick="rmf.yinyong()")
i.fa-solid.fa-message
span='引用文本评论'
.rightMenu-group.rightMenu-line.hide#menu-too
a.rightMenu-item(href="javascript:window.open(window.getSelection().toString());window.location.reload();")
i.fa.fa-link
span='转到链接'
.rightMenu-group.rightMenu-line.hide#menu-paste
a.rightMenu-item(href='javascript:rmf.paste()')
i.fa.fa-copy
span='粘贴'
.rightMenu-group.rightMenu-line.hide#menu-post
a.rightMenu-item(href="#post-comment")
i.fas.fa-comment
span='空降评论'
a.rightMenu-item(href="javascript:rmf.copyWordsLink()")
i.fa.fa-link
span='复制本文地址'
.rightMenu-group.rightMenu-line.hide#menu-to
a.rightMenu-item(href="javascript:rmf.openWithNewTab()")
i.fa.fa-window-restore
span='新窗口打开'
a.rightMenu-item#menu-too(href="javascript:rmf.open()")
i.fa.fa-link
span='转到链接'
a.rightMenu-item(href="javascript:rmf.copyLink()")
i.fa.fa-copy
span='复制链接'
.rightMenu-group.rightMenu-line.hide#menu-img
a.rightMenu-item(href="javascript:rmf.saveAs()")
i.fa.fa-download
span='保存图片'
a.rightMenu-item(href="javascript:rmf.openWithNewTab()")
i.fa.fa-window-restore
span='在新窗口打开'
a.rightMenu-item(href="javascript:rmf.click()")
i.fa.fa-arrows-alt
span='全屏显示'
a.rightMenu-item(href="javascript:rmf.copyLink()")
i.fa.fa-copy
span='复制图片链接'
.rightMenu-group.rightMenu-line
a.rightMenu-item(href="javascript:randomPost()")
i.fa.fa-paper-plane
span='随便逛逛'
a.rightMenu-item(href="javascript:rmf.switchDarkMode();")
i.fa.fa-moon
span='昼夜切换'
a.rightMenu-item(href="javascript:rmf.translate();")
i.iconfont.icon-fanti
span='繁简转换'
if is_post()||is_page()
a.rightMenu-item(href="javascript:rmf.switchReadMode();")
i.fa.fa-book
span='阅读模式'
//a.rightMenu-item(href="javascript:toggleWinbox();")
// i.fas.fa-cog
// span='博客设置'
a.rightMenu-item(href="javascript:rmf.fullScreen();")
i.fas.fa-expand
span#fullScreenText='进入全屏'

里面有一些图标用的iconfont的,请自行替换


添加CSS

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
/* rightMenu */
#rightMenu{
display: none;
position: fixed;
width: 160px;
height: fit-content;
top: 10%;
left: 10%;
background-color: var(--card-bg);
border: 1px solid var(--font-color);
border-radius: 8px;
z-index: 100;
}
#rightMenu .rightMenu-group{
padding: 7px 6px;
}
#rightMenu .rightMenu-group:not(:nth-last-child(1)){
border-bottom: 1px solid var(--font-color);
}
#rightMenu .rightMenu-group.rightMenu-small{
display: flex;
justify-content: space-between;
}
#rightMenu .rightMenu-group .rightMenu-item{
height: 30px;
line-height: 30px;
border-radius: 8px;
transition: 0.3s;
color: var(--font-color);
}
#rightMenu .rightMenu-group.rightMenu-line .rightMenu-item{
display: flex;
height: 40px;
line-height: 40px;
padding: 0 4px;
}
#rightMenu .rightMenu-group .rightMenu-item:hover{
background-color: var(--text-bg-hover);
}
#rightMenu .rightMenu-group .rightMenu-item i{
display: inline-block;
text-align: center;
line-height: 30px;
width: 30px;
height: 30px;
padding: 0 5px;
}
#rightMenu .rightMenu-group .rightMenu-item span{
line-height: 30px;
}

#rightMenu .rightMenu-group.rightMenu-line .rightMenu-item *{
height: 40px;
line-height: 40px;
}
.rightMenu-group.hide{
display: none;
}

主题配置文件_config.butterfly.yml添加

1
2
3
4
5
6
inject:
head:
- <link rel="stylesheet" href="/css/rightMenu.css">
- ...
bottom:
- ...


Javascript添加

创建 [blogRoot]/source/js/rightMenu.js

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
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
/*
* @Description: 右键菜单js
* @Author: 5t5
* @Time: 2024/1/26 17:24
*/
//22.12.8 update:add mask
//22.12.9 update: add search in this page
function setMask(){//设置遮罩层
if(document.getElementsByClassName("rmMask")[0] !== undefined){
return document.getElementsByClassName("rmMask")[0];
}
mask = document.createElement('div');
mask.className = "rmMask";
mask.style.width = window.innerWidth + 'px';
mask.style.height = window.innerHeight + 'px';
mask.style.background = '#fff';
mask.style.opacity = '.0';
mask.style.position = 'fixed';
mask.style.top = '0';
mask.style.left = '0';
mask.style.zIndex = 998;
document.body.appendChild(mask);
document.getElementById("rightMenu").style.zIndex=19198;
return mask;
}

function insertAtCursor(myField, myValue) {

//IE 浏览器
if (document.selection) {
myField.focus();
sel = document.selection.createRange();
sel.text = myValue;
sel.select();
}

//FireFox、Chrome等
else if (myField.selectionStart || myField.selectionStart == '0') {
var startPos = myField.selectionStart;
var endPos = myField.selectionEnd;

// 保存滚动条
var restoreTop = myField.scrollTop;
myField.value = myField.value.substring(0, startPos) + myValue + myField.value.substring(endPos, myField.value.length);

if (restoreTop > 0) {
myField.scrollTop = restoreTop;
}

myField.focus();
myField.selectionStart = startPos + myValue.length;
myField.selectionEnd = startPos + myValue.length;
} else {
myField.value += myValue;
myField.focus();
}
}
let rmf = {};
rmf.showRightMenu = function (isTrue, x = 0, y = 0) {
let $rightMenu = $('#rightMenu');
$rightMenu.css('top', x + 'px').css('left', y + 'px');

if (isTrue) {
$rightMenu.show();
} else {
$rightMenu.hide();
}
}
rmf.switchDarkMode = function () {
const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
if (nowMode === 'light') {
activateDarkMode()
saveToLocal.set('theme', 'dark', 2)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
} else {
activateLightMode()
saveToLocal.set('theme', 'light', 2)
GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day)
}
// handle some cases
typeof utterancesTheme === 'function' && utterancesTheme()
typeof FB === 'object' && window.loadFBComment()
window.DISQUS && document.getElementById('disqus_thread').children.length && setTimeout(() => window.disqusReset(), 200)
};
rmf.yinyong=function(){
var e = document.getElementsByClassName("el-textarea__inner")[0],
t = document.createEvent("HTMLEvents");
t.initEvent("input", !0, !0), e.value = d.value = "> "+getSelection().toString()+"\n\n", e.dispatchEvent(t);
console.log(getSelection().toString());
document.getElementsByClassName("el-textarea__inner")[0].value="> "+getSelection().toString()+"\n\n";
Snackbar.show({
text: '为保证最佳评论阅读体验,建议不要删除空行',
pos: 'top-center',
showAction: false,
})
}
rmf.copyWordsLink = function () {
let url = window.location.href
let txa = document.createElement("textarea");
txa.value = url;
document.body.appendChild(txa)
txa.select();
document.execCommand("Copy");
document.body.removeChild(txa);
Snackbar.show({
text: '链接复制成功!快去分享吧!',
pos: 'top-right',
showAction: false
});
}
rmf.switchReadMode = function () {
const $body = document.body
$body.classList.add('read-mode')
const newEle = document.createElement('button')
newEle.type = 'button'
newEle.className = 'fas fa-sign-out-alt exit-readmode'
$body.appendChild(newEle)

function clickFn() {
$body.classList.remove('read-mode')
newEle.remove()
newEle.removeEventListener('click', clickFn)
}

newEle.addEventListener('click', clickFn)
}
rmf.fullScreen = function () {
const fullScreenText = document.getElementById('fullScreenText');

if (!rmf.isFull) {
// 获取页面元素
const element = document.documentElement;

// 判断浏览器是否支持全屏API
if (element.requestFullscreen) {
// 进入全屏
element.requestFullscreen();

// 在进入全屏时,将控制台内容隐藏
console.clear(); // 清除控制台内容
console.log("Entering fullscreen. Console content is cleared.");
} else {
console.error("Fullscreen API is not supported in this browser.");
}

rmf.isFull = true;
fullScreenText.textContent = "退出全屏"; // 设置 span 内容

} else {
// 退出全屏
if (document.exitFullscreen) {
document.exitFullscreen();

console.log("Exiting fullscreen.");
} else {
console.error("Fullscreen exit is not supported in this browser.");
}

rmf.isFull = false;
fullScreenText.textContent = "进入全屏"; // 设置 span 内容
}
}


//复制选中文字
rmf.copySelect = function () {
document.execCommand('Copy', false, null);
//这里可以写点东西提示一下 已复制
}

//回到顶部
rmf.scrollToTop = function () {
document.getElementsByClassName("menus_items")[1].setAttribute("style","");
//document.getElementById("name-container").setAttribute("style","display:none");
btf.scrollToDest(0, 500);
}
rmf.translate = function () {
document.getElementById("translateLink").click();
}
rmf.searchinThisPage=()=>{
const searchTarget = document.querySelector('#algolia-search .search-dialog')
searchTarget.style.display = 'block';
// 获取搜索框元素
const searchBoxInput = document.getElementsByClassName("ais-SearchBox-input")[0];
// 设置搜索框的值为当前选中的文本
searchBoxInput.value = window.getSelection().toString();
// 模拟按下回车键的事件
const enterKeyEvent = new KeyboardEvent('keyup', { key: 'Enter', keyCode: 13 });
searchBoxInput.dispatchEvent(enterKeyEvent);
//var evt = document.createEvent("HTMLEvents");
//evt.initEvent("input", false, false);
//document.getElementsByClassName("local-search-box--input")[0].dispatchEvent(evt);
}

document.body.addEventListener('touchmove', function(e){

}, { passive: false });
function popupMenu() {
//window.oncontextmenu=function(){return false;}
window.oncontextmenu = function (event) {
if(event.ctrlKey||document.body.clientWidth<900) return true;
$('.rightMenu-group.hide').hide();
if (document.getSelection().toString()) {
$('#menu-text').show();
}
if (document.getElementById('post')) {
$('#menu-post').show();
} else {
if (document.getElementById('page')) {
$('#menu-post').show();
}
}
var el = window.document.body;
el = event.target;
var a=/^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\*\+,;=.]+$/
if (a.test(window.getSelection().toString())&&el.tagName!="A"){
$('#menu-too').show()
}
if (el.tagName == 'A') {
$('#menu-to').show()
rmf.open = function () {
if(el.href.indexOf("http://")==-1&&el.href.indexOf("https://")==-1||el.href.indexOf("yisous.xyz")!=-1){
pjax.loadUrl(el.href)
}
else{
location.href = el.href
}
}
rmf.openWithNewTab = function () {
window.open(el.href);
// window.location.reload();
}
rmf.copyLink = function () {
let url = el.href
let txa = document.createElement("textarea");
txa.value = url;
document.body.appendChild(txa)
txa.select();
document.execCommand("Copy");
document.body.removeChild(txa);
}
}
if (el.tagName == 'IMG') {
$('#menu-img').show()
rmf.openWithNewTab = function () {
window.open(el.src);
// window.location.reload();
}
rmf.click = function () {
el.click()
}
rmf.copyLink = function () {
let url = el.src
let txa = document.createElement("textarea");
txa.value = url;
document.body.appendChild(txa)
txa.select();
document.execCommand("Copy");
document.body.removeChild(txa);
}
rmf.saveAs=function(){
var a = document.createElement('a');
var url = el.src;
var filename = url.split("/")[-1];
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}
} else if (el.tagName == "TEXTAREA" || el.tagName == "INPUT") {
$('#menu-paste').show();
// rmf.paste=function(){
// input.addEventListener('paste', async event => {
// event.preventDefault();
// const text = await navigator.clipboard.readText();
// el.value+=text;
// });
// }
rmf.paste = function () {
navigator.permissions
.query({
name: 'clipboard-read'
})
.then(result => {
if (result.state == 'granted' || result.state == 'prompt') {
//读取剪贴板
navigator.clipboard.readText().then(text => {
console.log(text)
insertAtCursor(el, text)
})
} else {
Snackbar.show({
text: '请允许读取剪贴板!',
pos: 'top-center',
showAction: false,
})
}
})
}
}
let pageX = event.clientX + 10;
let pageY = event.clientY;
let rmWidth = $('#rightMenu').width();
let rmHeight = $('#rightMenu').height();
if (pageX + rmWidth > window.innerWidth) {
pageX -= rmWidth + 10;
}
if (pageY + rmHeight > window.innerHeight) {
pageY -= pageY + rmHeight - window.innerHeight;
}
mask=setMask();
window.onscroll=()=>{
rmf.showRightMenu(false);
window.onscroll=()=>{}
if (mask) {
// 判断 mask 是否有父节点
if (mask.parentNode) {
// 移除 mask 的父节点中的 mask
mask.parentNode.removeChild(mask);
} else {
console.error("Mask does not have a parent node.");
}
}
}
$(".rightMenu-item").click(()=>{
if (mask) {
// 判断 mask 是否有父节点
if (mask.parentNode) {
// 移除 mask 的父节点中的 mask
mask.parentNode.removeChild(mask);
} else {
console.error("Mask does not have a parent node.");
}
}
})
$(window).resize(()=>{
rmf.showRightMenu(false);
if (mask) {
// 判断 mask 是否有父节点
if (mask.parentNode) {
// 移除 mask 的父节点中的 mask
mask.parentNode.removeChild(mask);
} else {
console.error("Mask does not have a parent node.");
}
}
})
mask.onclick=()=>{
if (mask) {
// 判断 mask 是否有父节点
if (mask.parentNode) {
// 移除 mask 的父节点中的 mask
mask.parentNode.removeChild(mask);
} else {
console.error("Mask does not have a parent node.");
}
}
}
rmf.showRightMenu(true, pageY, pageX);
return false;
};

window.addEventListener('click', function () {
rmf.showRightMenu(false);
});
}
if (!(navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
popupMenu()
}
const box = document.documentElement

function addLongtabListener(target, callback) {
let timer = 0 // 初始化timer

target.ontouchstart = () => {
timer = 0 // 重置timer
timer = setTimeout(() => {
callback();
timer = 0
}, 380) // 超时器能成功执行,说明是长按
}

target.ontouchmove = () => {
clearTimeout(timer) // 如果来到这里,说明是滑动
timer = 0
}

target.ontouchend = () => { // 到这里如果timer有值,说明此触摸时间不足380ms,是点击
if (timer) {
clearTimeout(timer)
}
}
}

addLongtabListener(box, popupMenu)

主题配置文件_config.butterfly.yml添加

1
2
3
4
5
6
7
8
inject:
head:
- ...
bottom:
- ...
- <script type="text/javascript" src="https://npm.elemecdn.com/jquery@latest/dist/jquery.min.js"></script>
- <script type="text/javascript" src="/js/rightMenu.js"></script>
- ...

本站测试效果