hexo-theme-volantis
Version:
Elegant and powerful theme for Hexo.
578 lines (527 loc) • 20.8 kB
JavaScript
const RightMenu = (() => {
const
rightMenuConfig = volantis.GLOBAL_CONFIG.plugins.rightmenu,
messageRightMenu = volantis.GLOBAL_CONFIG.plugins.message.enable && volantis.GLOBAL_CONFIG.plugins.message.rightmenu.enable;
const
fn = {},
_rightMenuWrapper = document.getElementById('rightmenu-wrapper'),
_rightMenuContent = document.getElementById('rightmenu-content'),
_printHtml = document.getElementById('printHtml'),
_menuMusic = document.getElementById('menuMusic'),
_readingModel = document.getElementById('readingModel'),
_readBkg = document.getElementById('read_bkg');
const
_menuLoad = document.querySelectorAll('.menuLoad-Content'),
_menuOption = document.querySelector('.menu-Option'),
_searchWord = document.querySelector('.menu-Option[data-fn-type="searchWord"]'),
_copyText = document.querySelector('.menu-Option[data-fn-type="copyText"]'),
_copyPaste = document.querySelector('.menu-Option[data-fn-type="copyPaste"]'),
_copySelect = document.querySelector('.menu-Option[data-fn-type="copySelect"]'),
_copyCut = document.querySelector('.menu-Option[data-fn-type="copyCut"]'),
_copyHref = document.querySelector('.menu-Option[data-fn-type="copyHref"]'),
_copySrc = document.querySelector('.menu-Option[data-fn-type="copySrc"]'),
_copyImg = document.querySelector('.menu-Option[data-fn-type="copyImg"]'),
_openTab = document.querySelector('.menu-Option[data-fn-type="openTab"]'),
_backward = document.querySelector('#menuMusic .backward'),
_toggle = document.querySelector('#menuMusic .toggle'),
_forward = document.querySelector('#menuMusic .forward');
const urlRegx = /^((https|http)?:\/\/)+[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/;
fn.init = () => {
DOMController.visible(_menuMusic, false);
DOMController.visible(_menuOption, false);
if (_readBkg) _readBkg.parentNode.removeChild(_readBkg);
const readBkg = document.createElement("div");
readBkg.className = "common_read_bkg common_read_hide";
readBkg.id = "read_bkg";
window.document.body.appendChild(readBkg);
}
fn.initEvent = () => {
window.document.oncontextmenu = (event) => {
if (event.ctrlKey || document.body.offsetWidth <= 500) {
fn.hideMenu();
return true;
}
return fn.popMenu(event);
}
_rightMenuWrapper.oncontextmenu = (event) => {
event.stopPropagation();
event.preventDefault();
return false;
}
window.removeEventListener('blur', fn.hideMenu);
window.addEventListener('blur', fn.hideMenu);
document.body.removeEventListener('click', fn.hideMenu);
document.body.addEventListener('click', fn.hideMenu);
if (_forward && _toggle && _forward) {
_backward.onclick = (e) => {
e.preventDefault();
e.stopPropagation();
RightMenuAplayer.aplayerBackward();
}
_toggle.onclick = (e) => {
e.preventDefault();
e.stopPropagation();
RightMenuAplayer.aplayerToggle();
}
_forward.onclick = (e) => {
e.preventDefault();
e.stopPropagation();
RightMenuAplayer.aplayerForward();
}
}
}
// 菜单位置设定
fn.popMenu = (event) => {
let mouseClientX = event.clientX;
let mouseClientY = event.clientY;
let screenWidth = document.documentElement.clientWidth || document.body.clientWidth;
let screenHeight = document.documentElement.clientHeight || document.body.clientHeight;
try {
fn.setMenuItem(event);
DOMController.visible(_rightMenuWrapper);
_rightMenuWrapper.focus();
_rightMenuWrapper.style.zIndex = '-2147483648';
let menuWidth = _rightMenuContent.offsetWidth;
let menuHeight = _rightMenuContent.offsetHeight;
let showLeft = mouseClientX + menuWidth > screenWidth ? mouseClientX - menuWidth + 10 : mouseClientX;
let showTop = mouseClientY + menuHeight > screenHeight ? mouseClientY - menuHeight + 10 : mouseClientY;
showTop = mouseClientY + menuHeight > screenHeight && showTop < menuHeight && mouseClientY < menuHeight ?
showTop + (screenHeight - menuHeight - showTop - 10) : showTop;
_rightMenuWrapper.style.left = showLeft + "px";
_rightMenuWrapper.style.top = showTop + "px";
_rightMenuWrapper.style.zIndex = '2147483648';
if (volantis.GLOBAL_CONFIG.plugins.message.rightmenu.notice) fn.showMessage();
} catch (error) {
_rightMenuWrapper.blur();
console.error(error);
return true;
}
return false;
}
// 消息提示
fn.showMessage = () => {
const NoticeRightMenu = localStorage.getItem('NoticeRightMenu') === 'true';
if (messageRightMenu && !NoticeRightMenu)
VolantisApp.message('右键菜单', '唤醒原系统菜单请使用:<kbd>Ctrl</kbd> + <kbd>右键</kbd>', {
icon: rightMenuConfig.faicon + ' fa-exclamation-square red',
time: 9000
}, () => {
localStorage.setItem('NoticeRightMenu', 'true')
});
}
// 菜单项设置
fn.setMenuItem = (event) => {
let optionFlag = false;
const eventTarget = event.target;
const selectText = window.getSelection().toString();
DOMController.visible(_openTab, false); // 隐藏新标签页打开
// 判断是否是输入框
if (eventTarget.tagName.toLowerCase() === 'input' || eventTarget.tagName.toLowerCase() === 'textarea') {
const inputStr = eventTarget.value;
// 全选
if (inputStr.length > 0) {
DOMController.visible(_copySelect);
_copySelect.onclick = () => {
event.preventDefault();
eventTarget.select();
}
} else {
DOMController.visible(_copySelect, false);
}
// 剪切
if (selectText) {
DOMController.visible(_copyCut);
_copyCut.onclick = () => {
const statrPos = eventTarget.selectionStart;
const endPos = eventTarget.selectionEnd;
fn.copyString(selectText);
eventTarget.value = inputStr.substring(0, statrPos) + inputStr.substring(endPos, inputStr.length);
eventTarget.selectionStart = statrPos;
eventTarget.selectionEnd = statrPos;
eventTarget.focus();
}
} else {
DOMController.visible(_copyCut, false);
}
// 粘贴
fn.readClipboard().then(text => {
// 如果剪切板存在内容
if (!!text) {
DOMController.visible(_copyPaste);
_copyPaste.onclick = () => {
fn.insertAtCaret(eventTarget, text);
}
} else {
DOMController.visible(_copyPaste, false);
}
}).catch((err) => {
console.error(err);
DOMController.visible(_copyPaste, false);
});
} else {
DOMController.visible(_copySelect, false);
DOMController.visible(_copyPaste, false);
DOMController.visible(_copyCut, false);
}
// 新标签打开链接
const eventHref = eventTarget.href;
if (!!eventHref && urlRegx.test(eventHref)) {
optionFlag = true;
DOMController.visible(_copyHref);
DOMController.visible(_openTab);
if (_copyHref) _copyHref.onclick = () => {
fn.copyString(eventHref);
}
_openTab.onclick = () => {
window.open(eventHref);
}
} else {
DOMController.visible(_copyHref, false);
}
// 新标签打开图片 & 复制图片链接
const eventSrc = eventTarget.currentSrc;
if (!!eventSrc && urlRegx.test(eventSrc)) {
optionFlag = true;
DOMController.visible(_copySrc);
DOMController.visible(_openTab);
_copySrc.onclick = () => {
fn.copyString(eventSrc);
}
_openTab.onclick = () => {
window.open(eventSrc);
}
} else {
DOMController.visible(_copySrc, false);
}
// 复制图片
if (!!eventSrc && urlRegx.test(eventSrc) && eventSrc.trimEnd().endsWith('.png')) {
optionFlag = true;
DOMController.visible(_copyImg);
_copyImg.onclick = () => {
fn.writeClipImg(event, flag => {
if (flag && messageRightMenu) VolantisApp.message('系统提示', '图片复制成功!', {
icon: rightMenuConfig.faicon + ' fa-images'
});
}, (error) => {
if (messageRightMenu) VolantisApp.message('系统提示', '复制失败:' + error, {
icon: rightMenuConfig.faicon + ' fa-exclamation-square red'
});
})
}
} else {
DOMController.visible(_copyImg, false);
}
// 复制文本
if (selectText) {
optionFlag = true;
DOMController.visible(_copyText);
DOMController.visible(_searchWord);
_copyText.onclick = () => {
fn.copyString(selectText);
}
!!_searchWord && (_searchWord.onclick = () => {
OpenSearch(selectText);
})
} else {
DOMController.visible(_copyText, false);
DOMController.visible(_searchWord, false);
}
// 打印
const _printArticle = document.querySelector('#post.article') || null;
const pathName = window.location.pathname;
if (!!_printArticle) {
DOMController.visible(_printHtml);
DOMController.visible(_readingModel);
if (_printHtml) {
_printHtml.onclick = () => {
if (window.location.pathname === pathName) {
const message = '是否打印当前页面?<br><em style="font-size: 80%">建议打印时勾选背景图形</em><br>';
if (messageRightMenu) VolantisApp.question('', message, {}, () => {
fn.printHtml();
})
} else {
fn.hideMenu();
}
}
}
if (_readingModel) {
_readingModel.onclick = () => {
if (window.location.pathname === pathName) {
fn.readingModel();
} else {
fn.readingModel();
}
}
}
} else {
DOMController.visible(_printHtml, false);
DOMController.visible(_readingModel, false);
}
if (volantis.GLOBAL_CONFIG.plugins.aplayer.enable
&& typeof RightMenuAplayer !== 'undefined'
&& RightMenuAplayer.APlayer.player !== undefined) {
if (rightMenuConfig.music_alwaysShow) {
DOMController.visible(_menuMusic);
} else if (RightMenuAplayer.APlayer.status === 'play' || RightMenuAplayer.APlayer.status === 'undefined') {
optionFlag = true;
DOMController.visible(_menuMusic);
} else {
DOMController.visible(_menuMusic, false);
}
} else {
DOMController.visible(_menuMusic, false);
}
_menuLoad.forEach(ele => {
DOMController.visible(ele, !optionFlag);
})
if (volantis.GLOBAL_CONFIG.plugins.aplayer.enable
&& rightMenuConfig.layout.includes('music')) {
RightMenuAplayer.checkAPlayer();
}
}
// 隐藏菜单
fn.hideMenu = () => {
DOMController.visible(_rightMenuWrapper, false);
}
// 复制字符串
fn.copyString = (str) => {
VolantisApp.utilWriteClipText(str)
.then(() => {
if (messageRightMenu) {
VolantisApp.messageCopyright();
}
}).catch(e => {
if (messageRightMenu) {
VolantisApp.message('系统提示', e, {
icon: rightMenuConfig.faicon + ' fa-exclamation-square red'
});
}
})
}
// 写入文本到剪切板
fn.writeClipText = (str) => {
try {
return navigator.clipboard
.writeText(str)
.then(() => {
return Promise.resolve()
})
.catch(err => {
return Promise.reject(err)
})
} catch (e) {
const input = document.createElement('input');
input.setAttribute('readonly', 'readonly');
document.body.appendChild(input);
input.setAttribute('value', str);
input.select();
try {
let result = document.execCommand('copy')
document.body.removeChild(input);
if (!result || result === 'unsuccessful') {
return Promise.reject('复制文本失败!')
} else {
return Promise.resolve()
}
} catch (e) {
document.body.removeChild(input);
return Promise.reject(
'当前浏览器不支持复制功能,请检查更新或更换其他浏览器操作!'
)
}
}
}
// 写入图片到剪切板
fn.writeClipImg = async function (event, success, error) {
const eventSrc = rightMenuConfig.customPicUrl.enable ?
event.target.currentSrc.replace(rightMenuConfig.customPicUrl.old, rightMenuConfig.customPicUrl.new) :
event.target.currentSrc;
const parentElement = event.target.parentElement;
try {
const data = await fetch(eventSrc);
const blob = await data.blob();
await navigator.clipboard
.write([
new ClipboardItem({
[blob.type]: blob
})
]).then(() => {
success(true);
}, (e) => {
console.error('图片复制失败:', e);
error(e);
});
} catch (e) {
const dom = document;
try {
if (dom.body.createTextRange) {
const textRange = document.body.createTextRange();
textRange.moveToElementText(parentElement);
textRange.select();
} else if (window.getSelection) {
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(parentElement);
selection.removeAllRanges();
selection.addRange(range);
}
document.execCommand('copy');
window.getSelection().removeAllRanges();
success(false);
} catch (e) {
console.error(e);
error('不支持复制当前图片!');
}
}
}
// 请求读取剪切板
fn.readClipboard = async () => {
const result = await navigator.permissions.query({
name: 'clipboard-read'
});
if (result.state === 'granted' || result.state === 'prompt') {
// 修改为 .read() 可以获取剪切板中的文字/图片
// 返回的是 ClipboardItem
return navigator.clipboard
.readText()
.then(text => text)
.catch(err => Promise.reject(err));
}
return Promise.reject(result);
}
// 粘贴文本
fn.insertAtCaret = (elemt, value) => {
const startPos = elemt.selectionStart,
endPos = elemt.selectionEnd;
if (document.selection) {
elemt.focus();
var sel = document.selection.createRange();
sel.text = value;
elemt.focus();
} else {
if (startPos || startPos == '0') {
var scrollTop = elemt.scrollTop;
elemt.value = elemt.value.substring(0, startPos) + value + elemt.value.substring(endPos, elemt.value.length);
elemt.focus();
elemt.selectionStart = startPos + value.length;
elemt.selectionEnd = startPos + value.length;
elemt.scrollTop = scrollTop;
} else {
elemt.value += value;
elemt.focus();
}
}
}
// 执行打印页面
fn.printHtml = () => {
if (volantis.isReadModel) fn.readingModel();
DOMController.setAttribute('details', 'open', 'true');
DOMController.remove('.cus-article-bkg');
DOMController.remove('.iziToast-overlay');
DOMController.remove('.iziToast-wrapper');
DOMController.remove('.prev-next');
DOMController.remove('footer');
DOMController.remove('#l_header');
DOMController.remove('#l_cover');
DOMController.remove('#l_side');
DOMController.remove('#comments');
DOMController.remove('#s-top');
DOMController.remove('#BKG');
DOMController.remove('#rightmenu-wrapper');
DOMController.remove('.nav-tabs');
DOMController.remove('.parallax-mirror');
DOMController.remove('.new-meta-item.share');
DOMController.remove('div.footer');
DOMController.setStyle('body', 'backgroundColor', 'unset');
DOMController.setStyle('#l_main', 'width', '100%');
DOMController.setStyle('#post', 'boxShadow', 'none');
DOMController.setStyle('#post', 'background', 'none');
DOMController.setStyle('#post', 'padding', '0');
DOMController.setStyle('h1', 'textAlign', 'center');
DOMController.setStyle('h1', 'fontWeight', '600');
DOMController.setStyle('h1', 'fontSize', '2rem');
DOMController.setStyle('h1', 'marginBottom', '20px');
DOMController.setStyle('.tab-pane', 'display', 'block');
DOMController.setStyle('.tab-content', 'borderTop', 'none');
DOMController.setStyle('.highlight>table pre', 'whiteSpace', 'pre-wrap');
DOMController.setStyle('.highlight>table pre', 'wordBreak', 'break-all');
DOMController.setStyle('.fancybox img', 'height', 'auto');
DOMController.setStyle('.fancybox img', 'weight', 'auto');
setTimeout(() => {
window.print();
document.body.innerHTML = '';
window.location.reload();
}, 50);
}
// 阅读模式
fn.readingModel = () => {
if (typeof ScrollReveal === 'function') ScrollReveal().clean('#comments');
DOMController.fadeToggle(document.querySelector('#l_header'))
DOMController.fadeToggle(document.querySelector('footer'))
DOMController.fadeToggle(document.querySelector('#s-top'))
DOMController.fadeToggle(document.querySelector('.article-meta#bottom'))
DOMController.fadeToggle(document.querySelector('.prev-next'))
DOMController.fadeToggle(document.querySelector('#l_side'))
DOMController.fadeToggle(document.querySelector('#comments'))
DOMController.toggleClass(document.querySelector('#l_main'), 'common_read')
DOMController.toggleClass(document.querySelector('#l_main'), 'common_read_main')
DOMController.toggleClass(document.querySelector('#l_body'), 'common_read')
DOMController.toggleClass(document.querySelector('#safearea'), 'common_read')
DOMController.toggleClass(document.querySelector('#pjax-container'), 'common_read')
DOMController.toggleClass(document.querySelector('#read_bkg'), 'common_read_hide')
DOMController.toggleClass(document.querySelector('h1'), 'common_read_h1')
DOMController.toggleClass(document.querySelector('#post'), 'post_read')
DOMController.toggleClass(document.querySelector('#l_cover'), 'read_cover')
DOMController.toggleClass(document.querySelector('.widget.toc-wrapper'), 'post_read')
volantis.isReadModel = volantis.isReadModel === undefined ? true : !volantis.isReadModel;
if (volantis.isReadModel) {
const option = {
backgroundColor: 'var(--color-read-post)',
icon: rightMenuConfig.faicon + ' fa-book-reader',
time: 5000
}
if (messageRightMenu) VolantisApp.message('系统提示', '阅读模式已开启,您可以点击屏幕空白处退出。', option);
document.querySelector('#l_body').removeEventListener('click', fn.readingModel);
document.querySelector('#l_body').addEventListener('click', (event) => {
if (DOMController.hasClass(event.target, 'common_read')) {
fn.readingModel();
}
});
} else {
document.querySelector('#l_body').removeEventListener('click', fn.readingModel);
document.querySelector('#post').removeEventListener('click', fn.readingModel);
}
}
return {
init: (notice = false) => {
fn.init();
fn.initEvent();
if (notice && messageRightMenu) VolantisApp.message('系统提示', '自定义右键注册成功。');
},
destroy: (notice = false) => {
fn.hideMenu();
window.document.oncontextmenu = () => {
return true
};
if (notice && messageRightMenu) VolantisApp.message('系统提示', '自定义右键注销成功。');
},
hideMenu: fn.hideMenu,
readingModel: fn.readingModel
}
})()
Object.freeze(RightMenu);
volantis.requestAnimationFrame(() => {
if (document.readyState !== 'loading') {
RightMenu.init();
volantis.pjax.send(() => {
RightMenu.hideMenu();
})
} else {
document.addEventListener("DOMContentLoaded", function () {
RightMenu.init();
volantis.pjax.send(() => {
RightMenu.hideMenu();
})
})
}
});