486 lines
14 KiB
JavaScript
486 lines
14 KiB
JavaScript
let halo = {
|
||
darkComment: () => {
|
||
if (document.querySelector('#comment div').shadowRoot.querySelector('.halo-comment-widget').classList !=
|
||
null) {
|
||
let commentDOMclass = document.querySelector('#comment div').shadowRoot.querySelector(
|
||
'.halo-comment-widget').classList
|
||
if (commentDOMclass.contains('light'))
|
||
commentDOMclass.replace('light', 'dark')
|
||
else
|
||
commentDOMclass.replace('dark', 'light')
|
||
}
|
||
|
||
},
|
||
|
||
dataCodeTheme: () => {
|
||
|
||
var t = document.documentElement.getAttribute('data-theme')
|
||
var e = document.querySelector("link[data-code-theme=light]"),
|
||
o = document.querySelector("link[data-code-theme=dark]");
|
||
(o || e) && ("light" === t ? (o.disabled = !0, e.disabled = !1) : (e.disabled = !0, o.disabled = !1))
|
||
},
|
||
|
||
/**
|
||
* 代码
|
||
* 只适用于halo的代码渲染
|
||
*/
|
||
addPrismTool: () => {
|
||
if (typeof Prism === 'undefined' || typeof document === 'undefined') {
|
||
return;
|
||
}
|
||
|
||
if (!Prism.plugins.toolbar) {
|
||
console.warn('Copy to Clipboard plugin loaded before Toolbar plugin.');
|
||
return;
|
||
}
|
||
|
||
const enable = GLOBAL_CONFIG.prism.enable;
|
||
if (!enable) return;
|
||
const isEnableTitle = GLOBAL_CONFIG.prism.enable_title;
|
||
const isEnableHr = GLOBAL_CONFIG.prism.enable_hr;
|
||
const isEnableLine = GLOBAL_CONFIG.prism.enable_line;
|
||
const isEnableCopy = GLOBAL_CONFIG.prism.enable_copy;
|
||
const isEnableExpander = GLOBAL_CONFIG.prism.enable_expander;
|
||
const prismLimit = GLOBAL_CONFIG.prism.prism_limit;
|
||
const isEnableHeightLimit = GLOBAL_CONFIG.prism.enable_height_limit;
|
||
|
||
// https://stackoverflow.com/a/30810322/7595472
|
||
|
||
/** @param {CopyInfo} copyInfo */
|
||
function fallbackCopyTextToClipboard(copyInfo) {
|
||
var textArea = document.createElement('textarea');
|
||
textArea.value = copyInfo.getText();
|
||
|
||
// Avoid scrolling to bottom
|
||
textArea.style.top = '0';
|
||
textArea.style.left = '0';
|
||
textArea.style.position = 'fixed';
|
||
|
||
document.body.appendChild(textArea);
|
||
textArea.focus();
|
||
textArea.select();
|
||
|
||
try {
|
||
var successful = document.execCommand('copy');
|
||
setTimeout(function() {
|
||
if (successful) {
|
||
copyInfo.success();
|
||
} else {
|
||
copyInfo.error();
|
||
}
|
||
}, 1);
|
||
} catch (err) {
|
||
setTimeout(function() {
|
||
copyInfo.error(err);
|
||
}, 1);
|
||
}
|
||
|
||
document.body.removeChild(textArea);
|
||
}
|
||
|
||
/** @param {CopyInfo} copyInfo */
|
||
function copyTextToClipboard(copyInfo) {
|
||
if (navigator.clipboard) {
|
||
navigator.clipboard.writeText(copyInfo.getText()).then(copyInfo.success, function() {
|
||
// try the fallback in case `writeText` didn't work
|
||
fallbackCopyTextToClipboard(copyInfo);
|
||
});
|
||
} else {
|
||
fallbackCopyTextToClipboard(copyInfo);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Selects the text content of the given element.
|
||
*
|
||
* @param {Element} element
|
||
*/
|
||
function selectElementText(element) {
|
||
// https://stackoverflow.com/a/20079910/7595472
|
||
window.getSelection().selectAllChildren(element);
|
||
}
|
||
|
||
/**
|
||
* Traverses up the DOM tree to find data attributes that override the default plugin settings.
|
||
*
|
||
* @param {Element} startElement An element to start from.
|
||
* @returns {Settings} The plugin settings.
|
||
* @typedef {Record<"copy" | "copy-error" | "copy-success" | "copy-timeout", string | number>} Settings
|
||
*/
|
||
function getSettings(startElement) {
|
||
/** @type {Settings} */
|
||
var settings = {
|
||
'copy': 'Copy',
|
||
'copy-error': 'Press Ctrl+C to copy',
|
||
'copy-success': 'Copied!',
|
||
'copy-timeout': 5000
|
||
};
|
||
|
||
var prefix = 'data-prismjs-';
|
||
for (var key in settings) {
|
||
var attr = prefix + key;
|
||
var element = startElement;
|
||
while (element && !element.hasAttribute(attr)) {
|
||
element = element.parentElement;
|
||
}
|
||
if (element) {
|
||
settings[key] = element.getAttribute(attr);
|
||
}
|
||
}
|
||
return settings;
|
||
}
|
||
|
||
var r = Prism.plugins.toolbar.hook = function(a) {
|
||
|
||
|
||
var r = a.element.parentNode;
|
||
var toolbar = r.nextElementSibling;
|
||
|
||
//标题
|
||
isEnableTitle && toolbar.classList.add("c-title")
|
||
//标题分割线
|
||
isEnableHr && toolbar.classList.add("c-hr")
|
||
var customItem = document.createElement("div");
|
||
customItem.className = 'custom-item absolute top-0'
|
||
|
||
//复制
|
||
if (isEnableCopy) {
|
||
var copy = document.createElement("i");
|
||
|
||
copy.className = 'haofont hao-icon-paste copy-button code-copy cursor-pointer'
|
||
customItem.appendChild(copy)
|
||
|
||
copy.addEventListener('click', function() {
|
||
copyTextToClipboard({
|
||
getText: function() {
|
||
return a.element.textContent;
|
||
},
|
||
success: function() {
|
||
btf.snackbarShow('复制成功')
|
||
setState('copy-success');
|
||
resetText();
|
||
},
|
||
error: function() {
|
||
setState('copy-error');
|
||
|
||
setTimeout(function() {
|
||
selectElementText(a.element);
|
||
}, 1);
|
||
|
||
resetText();
|
||
}
|
||
});
|
||
|
||
});
|
||
|
||
}
|
||
|
||
const prismToolsFn = function(e) {
|
||
const $target = e.target.classList;
|
||
if ($target.contains("code-expander")) prismShrinkFn(this);
|
||
};
|
||
|
||
//折叠
|
||
if (isEnableExpander) {
|
||
var expander = document.createElement("i");
|
||
expander.className =
|
||
'fa-sharp fa-solid haofont hao-icon-angle-down code-expander cursor-pointer'
|
||
customItem.appendChild(expander)
|
||
|
||
expander.addEventListener('click', prismToolsFn)
|
||
|
||
|
||
}
|
||
|
||
const expandCode = function() {
|
||
this.classList.toggle("expand-done");
|
||
this.style.display = "none";
|
||
r.classList.toggle("expand-done");
|
||
};
|
||
|
||
if (isEnableHeightLimit && r.offsetHeight > prismLimit) {
|
||
|
||
r.classList.add("close")
|
||
const ele = document.createElement("div");
|
||
ele.className = "code-expand-btn";
|
||
ele.innerHTML = '<i class="haofont hao-icon-angle-double-down"></i>';
|
||
ele.addEventListener("click", expandCode);
|
||
r.offsetParent.appendChild(ele);
|
||
}
|
||
|
||
const prismShrinkFn = ele => {
|
||
const $nextEle = r.offsetParent.lastElementChild.classList
|
||
toolbar.classList.toggle('c-expander')
|
||
r.classList.toggle("expand-done-expander");
|
||
if (toolbar.classList.contains('c-expander')) {
|
||
r.firstElementChild.style.display = "none";
|
||
if ($nextEle.contains('code-expand-btn')) {
|
||
r.offsetParent.lastElementChild.style.display = "none";
|
||
}
|
||
} else {
|
||
r.firstElementChild.style.display = "block";
|
||
if ($nextEle.contains('code-expand-btn') && !r.classList.contains('expand-done')) {
|
||
r.offsetParent.lastElementChild.style.display = "block";
|
||
}
|
||
}
|
||
|
||
};
|
||
|
||
|
||
toolbar.appendChild(customItem)
|
||
|
||
var settings = getSettings(a.element);
|
||
|
||
|
||
function resetText() {
|
||
setTimeout(function() {
|
||
setState('copy');
|
||
}, settings['copy-timeout']);
|
||
}
|
||
|
||
/** @param {"copy" | "copy-error" | "copy-success"} state */
|
||
function setState(state) {
|
||
copy.setAttribute('data-copy-state', state);
|
||
}
|
||
|
||
};
|
||
Prism.hooks.add("complete", r)
|
||
},
|
||
|
||
addScript: (e, t, n) => {
|
||
if (document.getElementById(e))
|
||
return n ? n() : void 0;
|
||
let a = document.createElement("script");
|
||
a.src = t,
|
||
a.id = e,
|
||
n && (a.onload = n),
|
||
document.head.appendChild(a)
|
||
},
|
||
|
||
danmu: () => {
|
||
const e = new EasyDanmakuMin({
|
||
el: "#danmu",
|
||
line: 10,
|
||
speed: 20,
|
||
hover: !0,
|
||
loop: !0
|
||
});
|
||
let t = saveToLocal.get("danmu");
|
||
if (t)
|
||
e.batchSend(t, !0);
|
||
else {
|
||
let n = [];
|
||
if (GLOBAL_CONFIG.source.comments.use == 'Twikoo') {
|
||
fetch(GLOBAL_CONFIG.source.twikoo.twikooUrl, {
|
||
method: "POST",
|
||
body: JSON.stringify({
|
||
event: "GET_RECENT_COMMENTS",
|
||
accessToken: GLOBAL_CONFIG.source.twikoo.accessToken,
|
||
includeReply: !1,
|
||
pageSize: 5
|
||
}),
|
||
headers: {
|
||
"Content-Type": "application/json"
|
||
}
|
||
}).then((e => e.json())).then((({
|
||
data: t
|
||
}) => {
|
||
t.forEach((e => {
|
||
null == e.avatar && (e.avatar =
|
||
"https://cravatar.cn/avatar/d615d5793929e8c7d70eab5f00f7f5f1?d=mp"
|
||
),
|
||
n.push({
|
||
avatar: e.avatar,
|
||
content: e.nick + ":" + btf.changeContent(e
|
||
.comment),
|
||
href: e.url + '#' + e.id
|
||
|
||
})
|
||
})),
|
||
e.batchSend(n, !0),
|
||
saveToLocal.set("danmu", n, .02)
|
||
}))
|
||
}
|
||
if (GLOBAL_CONFIG.source.comments.use == 'Artalk') {
|
||
const statheaderList = {
|
||
method: 'GET',
|
||
headers: {
|
||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
||
'Origin': window.location.origin
|
||
}
|
||
// ,
|
||
// body: new URLSearchParams({
|
||
// 'site_name': GLOBAL_CONFIG.source.artalk.siteName,
|
||
// 'limit': '100',
|
||
// 'type': 'latest_comments'
|
||
// })
|
||
}
|
||
const queryParams = new URLSearchParams({
|
||
'site_name': GLOBAL_CONFIG.source.artalk.siteName,
|
||
'limit': '100'
|
||
});
|
||
|
||
fetch(GLOBAL_CONFIG.source.artalk.artalkUrl + 'api/v2/stats/latest_comments?' + queryParams
|
||
.toString(),
|
||
statheaderList)
|
||
.then((e => e.json())).then((({
|
||
data: t
|
||
}) => {
|
||
t.forEach((e => {
|
||
n.push({
|
||
avatar: 'https://cravatar.cn/avatar/' + e
|
||
.email_encrypted + '?d=mp&s=240',
|
||
content: e.nick + ":" + btf.changeContent(e
|
||
.content_marked),
|
||
href: e.page_url + '#atk-comment-' + e.id
|
||
|
||
})
|
||
})),
|
||
e.batchSend(n, !0),
|
||
saveToLocal.set("danmu", n, .02)
|
||
}))
|
||
}
|
||
if (GLOBAL_CONFIG.source.comments.use == 'Waline') {
|
||
const loadWaline = () => {
|
||
Waline.RecentComments({
|
||
serverURL: GLOBAL_CONFIG.source.waline.serverURL,
|
||
count: 50
|
||
}).then(({
|
||
comments
|
||
}) => {
|
||
const walineArray = comments.map(e => {
|
||
return {
|
||
'content': e.nick + ":" + btf.changeContent(e.comment),
|
||
'avatar': e.avatar,
|
||
'href': e.url + '#' + e.objectId,
|
||
}
|
||
})
|
||
e.batchSend(walineArray, !0),
|
||
saveToLocal.set("danmu", walineArray, .02)
|
||
})
|
||
}
|
||
if (typeof Waline === 'object') loadWaline()
|
||
else getScript(GLOBAL_CONFIG.source.waline.js).then(loadWaline)
|
||
}
|
||
|
||
}
|
||
document.getElementById("danmuBtn").innerHTML =
|
||
"<button class=\"hideBtn\" onclick=\"document.getElementById('danmu').classList.remove('hidedanmu')\">显示弹幕</button> <button class=\"hideBtn\" onclick=\"document.getElementById('danmu').classList.add('hidedanmu')\">隐藏弹幕</button>"
|
||
},
|
||
|
||
changeMarginLeft(element) {
|
||
var randomMargin = Math.floor(Math.random() * 901) + 100; // 生成100-1000之间的随机数
|
||
element.style.marginLeft = randomMargin + 'px';
|
||
},
|
||
|
||
getTopSponsors() {
|
||
var show_num = GLOBAL_CONFIG.source.power.showNum;
|
||
var url = GLOBAL_CONFIG.source.power.url;
|
||
|
||
function getPower() {
|
||
const url = GLOBAL_CONFIG.source.power.url;
|
||
let powerStar = document.getElementById("power-star")
|
||
powerStar.href = GLOBAL_CONFIG.source.power.powerLink
|
||
fetch(url)
|
||
.then(response => {
|
||
// 检查响应状态码
|
||
if (!response.ok) {
|
||
// 如果响应状态码不是 200,抛出一个错误
|
||
powerStar.innerHTML = `
|
||
<div id="power-star-image" style="background-image: url('/themes/theme-hao/assets/images/afadian/afadian.webp')">
|
||
</div>
|
||
<div class="power-star-body">
|
||
<div id="power-star-title">还没有人赞助~</div>
|
||
<div id="power-star-desc">为爱发电,点击赞助</div>
|
||
</div>`;
|
||
}
|
||
return response.json(); // 只有在状态码为 200 时才解析 JSON
|
||
})
|
||
.then(data => {
|
||
if (200 === data["ec"]) {
|
||
const values = data["data"]["list"];
|
||
saveToLocal.set('power-data', JSON.stringify(values), 10 / (60 * 24))
|
||
renderer(values);
|
||
}
|
||
})
|
||
.catch(error => {
|
||
powerStar.innerHTML = `
|
||
<div id="power-star-image" style="background-image: url('/themes/theme-hao/assets/images/afadian/afadian.webp')">
|
||
</div>
|
||
<div class="power-star-body">
|
||
<div id="power-star-title">还没有人赞助~</div>
|
||
<div id="power-star-desc">为爱发电,点击赞助</div>
|
||
</div>`;
|
||
console.error(error);
|
||
})
|
||
}
|
||
|
||
function renderer(values) {
|
||
var data = getArrayItems(values, 1);
|
||
let powerStar = document.getElementById("power-star")
|
||
if (values.length === 0) {
|
||
powerStar.href = GLOBAL_CONFIG.source.power.powerLink
|
||
powerStar.innerHTML = `
|
||
<div id="power-star-image" style="background-image: url('/themes/theme-hao/assets/images/afadian/afadian.webp')">
|
||
</div>
|
||
<div class="power-star-body">
|
||
<div id="power-star-title">还没有人赞助~</div>
|
||
<div id="power-star-desc">为爱发电,点击赞助</div>
|
||
</div>`;
|
||
} else {
|
||
if (powerStar) {
|
||
powerStar.href = "https://afdian.net/u/" + data[0]["user"].user_id
|
||
powerStar.innerHTML = `
|
||
<div id="power-star-image" style="background-image: url(${data[0]["user"].avatar})">
|
||
</div>
|
||
<div class="power-star-body">
|
||
<div id="power-star-title">${data[0]["user"].name}</div>
|
||
<div id="power-star-desc">更多支持,为爱发电</div>
|
||
</div>`;
|
||
}
|
||
|
||
if (values.length > 1) {
|
||
var i = 0;
|
||
var htmlText = '';
|
||
for (let value of values) {
|
||
if (i > parseInt(show_num)) {
|
||
break;
|
||
}
|
||
htmlText +=
|
||
` <a href="${"https://afdian.net/u/" + value["user"]["user_id"]}" rel="external nofollow" target="_blank" th:title="${value["user"]["name"]}">${value["user"]["name"]}</a>`;
|
||
i = i + 1;
|
||
}
|
||
if (document.getElementById("power-item-link")) {
|
||
document.getElementById("power-item-link").innerHTML = htmlText;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
function init() {
|
||
const data = saveToLocal.get('power-data')
|
||
if (data) {
|
||
renderer(JSON.parse(data))
|
||
} else {
|
||
getPower();
|
||
}
|
||
}
|
||
|
||
document.getElementById("power-star") && init()
|
||
},
|
||
|
||
checkAd() {
|
||
var default_enable = GLOBAL_CONFIG.source.footer.default_enable
|
||
if (default_enable) {
|
||
var adElement = document.getElementById("footer-banner");
|
||
var notMusic = document.body.getAttribute("data-type") != "music"; // 检测是否为音乐页面
|
||
if ((adElement.offsetWidth <= 0 || adElement.offsetHeight <= 0) && notMusic) {
|
||
// 元素不可见,可能被拦截
|
||
console.log("Element may be blocked by AdBlocker Ultimate");
|
||
alert("页脚信息可能被AdBlocker Ultimate拦截,请检查广告拦截插件!")
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
} |