fix theme...
This commit is contained in:
438
themes/anzhiyu/source/js/anzhiyu/ai_abstract.js
Normal file
438
themes/anzhiyu/source/js/anzhiyu/ai_abstract.js
Normal file
@@ -0,0 +1,438 @@
|
||||
(function () {
|
||||
const {
|
||||
randomNum,
|
||||
basicWordCount,
|
||||
btnLink,
|
||||
key: AIKey,
|
||||
Referer: AIReferer,
|
||||
gptName,
|
||||
switchBtn,
|
||||
mode: initialMode,
|
||||
} = GLOBAL_CONFIG.postHeadAiDescription;
|
||||
|
||||
const { title, postAI, pageFillDescription } = GLOBAL_CONFIG_SITE;
|
||||
|
||||
let lastAiRandomIndex = -1;
|
||||
let animationRunning = true;
|
||||
let mode = initialMode;
|
||||
let refreshNum = 0;
|
||||
let prevParam;
|
||||
let audio = null;
|
||||
let isPaused = false;
|
||||
let summaryID = null;
|
||||
|
||||
const post_ai = document.querySelector(".post-ai-description");
|
||||
const aiTitleRefreshIcon = post_ai.querySelector(".ai-title .anzhiyufont.anzhiyu-icon-arrow-rotate-right");
|
||||
let aiReadAloudIcon = post_ai.querySelector(".anzhiyu-icon-circle-dot");
|
||||
const explanation = post_ai.querySelector(".ai-explanation");
|
||||
|
||||
let aiStr = "";
|
||||
let aiStrLength = "";
|
||||
let delayInit = 600;
|
||||
let indexI = 0;
|
||||
let indexJ = 0;
|
||||
let timeouts = [];
|
||||
let elapsed = 0;
|
||||
|
||||
const observer = createIntersectionObserver();
|
||||
const aiFunctions = [introduce, aiTitleRefreshIconClick, aiRecommend, aiGoHome];
|
||||
|
||||
const aiBtnList = post_ai.querySelectorAll(".ai-btn-item");
|
||||
const filteredHeadings = Array.from(aiBtnList).filter(heading => heading.id !== "go-tianli-blog");
|
||||
filteredHeadings.forEach((item, index) => {
|
||||
item.addEventListener("click", () => {
|
||||
aiFunctions[index]();
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById("ai-tag").addEventListener("click", onAiTagClick);
|
||||
aiTitleRefreshIcon.addEventListener("click", onAiTitleRefreshIconClick);
|
||||
document.getElementById("go-tianli-blog").addEventListener("click", () => {
|
||||
window.open(btnLink, "_blank");
|
||||
});
|
||||
aiReadAloudIcon.addEventListener("click", readAloud);
|
||||
|
||||
async function readAloud() {
|
||||
if (!summaryID) {
|
||||
anzhiyu.snackbarShow("摘要还没加载完呢,请稍后。。。");
|
||||
return;
|
||||
}
|
||||
aiReadAloudIcon = post_ai.querySelector(".anzhiyu-icon-circle-dot");
|
||||
aiReadAloudIcon.style.opacity = "0.2";
|
||||
if (audio && !isPaused) {
|
||||
audio.pause();
|
||||
isPaused = true;
|
||||
aiReadAloudIcon.style.opacity = "1";
|
||||
aiReadAloudIcon.style.animation = "";
|
||||
aiReadAloudIcon.style.cssText = "animation: ''; opacity: 1;cursor: pointer;";
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio && isPaused) {
|
||||
audio.play();
|
||||
isPaused = false;
|
||||
aiReadAloudIcon.style.cssText = "animation: breathe .5s linear infinite; opacity: 0.2;cursor: pointer";
|
||||
return;
|
||||
}
|
||||
|
||||
const options = {
|
||||
key: AIKey,
|
||||
Referer: AIReferer,
|
||||
};
|
||||
const requestParams = new URLSearchParams({
|
||||
key: options.key,
|
||||
id: summaryID,
|
||||
});
|
||||
|
||||
const requestOptions = {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: options.Referer,
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(`https://summary.tianli0.top/audio?${requestParams}`, requestOptions);
|
||||
if (response.status === 403) {
|
||||
console.error("403 refer与key不匹配。");
|
||||
} else if (response.status === 500) {
|
||||
console.error("500 系统内部错误");
|
||||
} else {
|
||||
const audioBlob = await response.blob();
|
||||
const audioURL = URL.createObjectURL(audioBlob);
|
||||
audio = new Audio(audioURL);
|
||||
audio.play();
|
||||
aiReadAloudIcon.style.cssText = "animation: breathe .5s linear infinite; opacity: 0.2;cursor: pointer";
|
||||
audio.addEventListener("ended", () => {
|
||||
audio = null;
|
||||
aiReadAloudIcon.style.opacity = "1";
|
||||
aiReadAloudIcon.style.animation = "";
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("请求发生错误❎");
|
||||
}
|
||||
}
|
||||
if (switchBtn) {
|
||||
document.getElementById("ai-Toggle").addEventListener("click", changeShowMode);
|
||||
}
|
||||
|
||||
aiAbstract();
|
||||
showAiBtn();
|
||||
|
||||
function createIntersectionObserver() {
|
||||
return new IntersectionObserver(
|
||||
entries => {
|
||||
let isVisible = entries[0].isIntersecting;
|
||||
animationRunning = isVisible;
|
||||
if (animationRunning) {
|
||||
delayInit = indexI === 0 ? 200 : 20;
|
||||
timeouts[1] = setTimeout(() => {
|
||||
if (indexJ) {
|
||||
indexI = 0;
|
||||
indexJ = 0;
|
||||
}
|
||||
if (indexI === 0) {
|
||||
explanation.innerHTML = aiStr.charAt(0);
|
||||
}
|
||||
requestAnimationFrame(animate);
|
||||
}, delayInit);
|
||||
}
|
||||
},
|
||||
{ threshold: 0 }
|
||||
);
|
||||
}
|
||||
|
||||
function animate(timestamp) {
|
||||
if (!animationRunning) {
|
||||
return;
|
||||
}
|
||||
if (!animate.start) animate.start = timestamp;
|
||||
elapsed = timestamp - animate.start;
|
||||
if (elapsed >= 20) {
|
||||
animate.start = timestamp;
|
||||
if (indexI < aiStrLength - 1) {
|
||||
let char = aiStr.charAt(indexI + 1);
|
||||
let delay = /[,.,。!?!?]/.test(char) ? 150 : 20;
|
||||
if (explanation.firstElementChild) {
|
||||
explanation.removeChild(explanation.firstElementChild);
|
||||
}
|
||||
explanation.innerHTML += char;
|
||||
let div = document.createElement("div");
|
||||
div.className = "ai-cursor";
|
||||
explanation.appendChild(div);
|
||||
indexI++;
|
||||
if (delay === 150) {
|
||||
post_ai.querySelector(".ai-explanation .ai-cursor").style.opacity = "0.2";
|
||||
}
|
||||
if (indexI === aiStrLength - 1) {
|
||||
observer.disconnect();
|
||||
explanation.removeChild(explanation.firstElementChild);
|
||||
}
|
||||
timeouts[0] = setTimeout(() => {
|
||||
requestAnimationFrame(animate);
|
||||
}, delay);
|
||||
}
|
||||
} else {
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
}
|
||||
|
||||
function clearTimeouts() {
|
||||
if (timeouts.length) {
|
||||
timeouts.forEach(item => {
|
||||
if (item) {
|
||||
clearTimeout(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function startAI(str, df = true) {
|
||||
indexI = 0;
|
||||
indexJ = 1;
|
||||
clearTimeouts();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
observer.disconnect();
|
||||
explanation.innerHTML = df ? "生成中. . ." : "请等待. . .";
|
||||
aiStr = str;
|
||||
aiStrLength = aiStr.length;
|
||||
observer.observe(post_ai);
|
||||
}
|
||||
|
||||
async function aiAbstract(num = basicWordCount) {
|
||||
if (mode === "tianli") {
|
||||
await aiAbstractTianli(num);
|
||||
} else {
|
||||
aiAbstractLocal();
|
||||
}
|
||||
}
|
||||
|
||||
async function aiAbstractTianli(num) {
|
||||
indexI = 0;
|
||||
indexJ = 1;
|
||||
clearTimeouts();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
observer.disconnect();
|
||||
|
||||
num = Math.max(10, Math.min(2000, num));
|
||||
const options = {
|
||||
key: AIKey,
|
||||
Referer: AIReferer,
|
||||
};
|
||||
const truncateDescription = (title + pageFillDescription).trim().substring(0, num);
|
||||
|
||||
const requestBody = {
|
||||
key: options.key,
|
||||
content: truncateDescription,
|
||||
url: location.href,
|
||||
};
|
||||
|
||||
const requestOptions = {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: options.Referer,
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
};
|
||||
console.info(truncateDescription.length);
|
||||
try {
|
||||
let animationInterval = null;
|
||||
let summary;
|
||||
if (animationInterval) clearInterval(animationInterval);
|
||||
animationInterval = setInterval(() => {
|
||||
const animationText = "生成中" + ".".repeat(indexJ);
|
||||
explanation.innerHTML = animationText;
|
||||
indexJ = (indexJ % 3) + 1;
|
||||
}, 500);
|
||||
const response = await fetch(`https://summary.tianli0.top/`, requestOptions);
|
||||
let result;
|
||||
if (response.status === 403) {
|
||||
result = {
|
||||
summary: "403 refer与key不匹配。",
|
||||
};
|
||||
} else if (response.status === 500) {
|
||||
result = {
|
||||
summary: "500 系统内部错误",
|
||||
};
|
||||
} else {
|
||||
result = await response.json();
|
||||
}
|
||||
|
||||
summary = result.summary.trim();
|
||||
summaryID = result.id;
|
||||
|
||||
setTimeout(() => {
|
||||
aiTitleRefreshIcon.style.opacity = "1";
|
||||
}, 300);
|
||||
if (summary) {
|
||||
startAI(summary);
|
||||
} else {
|
||||
startAI("摘要获取失败!!!请检查Tianli服务是否正常!!!");
|
||||
}
|
||||
clearInterval(animationInterval);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
explanation.innerHTML = "发生异常" + error;
|
||||
}
|
||||
}
|
||||
|
||||
function aiAbstractLocal() {
|
||||
const strArr = postAI.split(",").map(item => item.trim());
|
||||
if (strArr.length !== 1) {
|
||||
let randomIndex = Math.floor(Math.random() * strArr.length);
|
||||
while (randomIndex === lastAiRandomIndex) {
|
||||
randomIndex = Math.floor(Math.random() * strArr.length);
|
||||
}
|
||||
lastAiRandomIndex = randomIndex;
|
||||
startAI(strArr[randomIndex]);
|
||||
} else {
|
||||
startAI(strArr[0]);
|
||||
}
|
||||
setTimeout(() => {
|
||||
aiTitleRefreshIcon.style.opacity = "1";
|
||||
}, 600);
|
||||
}
|
||||
|
||||
function aiRecommend() {
|
||||
indexI = 0;
|
||||
indexJ = 1;
|
||||
clearTimeouts();
|
||||
animationRunning = false;
|
||||
elapsed = 0;
|
||||
explanation.innerHTML = "生成中. . .";
|
||||
aiStr = "";
|
||||
aiStrLength = "";
|
||||
observer.disconnect();
|
||||
timeouts[2] = setTimeout(() => {
|
||||
explanation.innerHTML = recommendList();
|
||||
}, 600);
|
||||
}
|
||||
|
||||
function recommendList() {
|
||||
let thumbnail = document.querySelectorAll(".relatedPosts-list a");
|
||||
if (!thumbnail.length) {
|
||||
const cardRecentPost = document.querySelector(".card-widget.card-recent-post");
|
||||
if (!cardRecentPost) return "";
|
||||
|
||||
thumbnail = cardRecentPost.querySelectorAll(".aside-list-item a");
|
||||
|
||||
let list = "";
|
||||
for (let i = 0; i < thumbnail.length; i++) {
|
||||
const item = thumbnail[i];
|
||||
list += `<div class="ai-recommend-item"><span class="index">${
|
||||
i + 1
|
||||
}:</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${
|
||||
item.title
|
||||
}" data-pjax-state="">${item.title}</a></div>`;
|
||||
}
|
||||
|
||||
return `很抱歉,无法找到类似的文章,你也可以看看本站最新发布的文章:<br /><div class="ai-recommend">${list}</div>`;
|
||||
}
|
||||
|
||||
let list = "";
|
||||
for (let i = 0; i < thumbnail.length; i++) {
|
||||
const item = thumbnail[i];
|
||||
list += `<div class="ai-recommend-item"><span>推荐${
|
||||
i + 1
|
||||
}:</span><a href="javascript:;" onclick="pjax.loadUrl('${item.href}')" title="${
|
||||
item.title
|
||||
}" data-pjax-state="">${item.title}</a></div>`;
|
||||
}
|
||||
|
||||
return `推荐文章:<br /><div class="ai-recommend">${list}</div>`;
|
||||
}
|
||||
|
||||
function aiGoHome() {
|
||||
startAI("正在前往博客主页...", false);
|
||||
timeouts[2] = setTimeout(() => {
|
||||
if (window.pjax) {
|
||||
pjax.loadUrl("/");
|
||||
} else {
|
||||
location.href = location.origin;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function introduce() {
|
||||
if (mode == "tianli") {
|
||||
startAI("我是文章辅助AI: TianliGPT,点击下方的按钮,让我生成本文简介、推荐相关文章等。");
|
||||
} else {
|
||||
startAI(`我是文章辅助AI: ${gptName} GPT,点击下方的按钮,让我生成本文简介、推荐相关文章等。`);
|
||||
}
|
||||
}
|
||||
|
||||
function aiTitleRefreshIconClick() {
|
||||
aiTitleRefreshIcon.click();
|
||||
}
|
||||
|
||||
function onAiTagClick() {
|
||||
if (mode === "tianli") {
|
||||
post_ai.querySelectorAll(".ai-btn-item").forEach(item => (item.style.display = "none"));
|
||||
document.getElementById("go-tianli-blog").style.display = "block";
|
||||
startAI(
|
||||
"你好,我是Tianli开发的摘要生成助理TianliGPT,是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示,你无法与我直接沟通,如果你也需要一个这样的AI摘要接口,可以在下方购买。"
|
||||
);
|
||||
} else {
|
||||
post_ai.querySelectorAll(".ai-btn-item").forEach(item => (item.style.display = "block"));
|
||||
document.getElementById("go-tianli-blog").style.display = "none";
|
||||
startAI(
|
||||
`你好,我是本站摘要生成助理${gptName} GPT,是一个基于GPT-4的生成式AI。我在这里只负责摘要的预生成和显示,你无法与我直接沟通。`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function onAiTitleRefreshIconClick() {
|
||||
const truncateDescription = (title + pageFillDescription).trim().substring(0, basicWordCount);
|
||||
|
||||
aiTitleRefreshIcon.style.opacity = "0.2";
|
||||
aiTitleRefreshIcon.style.transitionDuration = "0.3s";
|
||||
aiTitleRefreshIcon.style.transform = "rotate(" + 360 * refreshNum + "deg)";
|
||||
if (truncateDescription.length <= basicWordCount) {
|
||||
let param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
while (param === prevParam || truncateDescription.length - param === prevParam) {
|
||||
param = truncateDescription.length - Math.floor(Math.random() * randomNum);
|
||||
}
|
||||
prevParam = param;
|
||||
aiAbstract(param);
|
||||
} else {
|
||||
let value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
while (value === prevParam || truncateDescription.length - value === prevParam) {
|
||||
value = Math.floor(Math.random() * randomNum) + basicWordCount;
|
||||
}
|
||||
aiAbstract(value);
|
||||
}
|
||||
refreshNum++;
|
||||
}
|
||||
|
||||
function changeShowMode() {
|
||||
mode = mode === "tianli" ? "local" : "tianli";
|
||||
if (mode === "tianli") {
|
||||
document.getElementById("ai-tag").innerHTML = "TianliGPT";
|
||||
|
||||
aiReadAloudIcon.style.opacity = "1";
|
||||
aiReadAloudIcon.style.cursor = "pointer";
|
||||
} else {
|
||||
aiReadAloudIcon.style.opacity = "0";
|
||||
aiReadAloudIcon.style.cursor = "auto";
|
||||
if ((document.getElementById("go-tianli-blog").style.display = "block")) {
|
||||
document.querySelectorAll(".ai-btn-item").forEach(item => (item.style.display = "block"));
|
||||
document.getElementById("go-tianli-blog").style.display = "none";
|
||||
}
|
||||
document.getElementById("ai-tag").innerHTML = gptName + " GPT";
|
||||
}
|
||||
aiAbstract();
|
||||
}
|
||||
|
||||
function showAiBtn() {
|
||||
if (mode === "tianli") {
|
||||
document.getElementById("ai-tag").innerHTML = "TianliGPT";
|
||||
} else {
|
||||
document.getElementById("ai-tag").innerHTML = gptName + " GPT";
|
||||
}
|
||||
}
|
||||
})();
|
||||
179
themes/anzhiyu/source/js/anzhiyu/comment_barrage.js
Normal file
179
themes/anzhiyu/source/js/anzhiyu/comment_barrage.js
Normal file
@@ -0,0 +1,179 @@
|
||||
if (document.querySelector(".comment-barrage")) {
|
||||
var commentBarrageConfig = {
|
||||
maxBarrage: GLOBAL_CONFIG.commentBarrageConfig.maxBarrage,
|
||||
barrageTime: GLOBAL_CONFIG.commentBarrageConfig.barrageTime,
|
||||
twikooUrl: GLOBAL_CONFIG.twikooEnvId,
|
||||
accessToken: GLOBAL_CONFIG.commentBarrageConfig.accessToken,
|
||||
mailMd5: GLOBAL_CONFIG.commentBarrageConfig.mailMd5,
|
||||
pageUrl: window.location.pathname,
|
||||
barrageTimer: [],
|
||||
barrageList: [],
|
||||
barrageIndex: 0,
|
||||
dom: document.querySelector(".comment-barrage"),
|
||||
};
|
||||
var commentInterval = null;
|
||||
var hoverOnCommentBarrage = false;
|
||||
|
||||
document.querySelector(".comment-barrage").addEventListener("mouseenter", function () {
|
||||
hoverOnCommentBarrage = true;
|
||||
});
|
||||
document.querySelector(".comment-barrage").addEventListener("mouseleave", function () {
|
||||
hoverOnCommentBarrage = false;
|
||||
});
|
||||
|
||||
function initCommentBarrage() {
|
||||
if (!commentBarrageConfig.dom) return;
|
||||
|
||||
var data = JSON.stringify({
|
||||
event: "COMMENT_GET",
|
||||
"commentBarrageConfig.accessToken": commentBarrageConfig.accessToken,
|
||||
url: commentBarrageConfig.pageUrl,
|
||||
});
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.withCredentials = true;
|
||||
xhr.addEventListener("readystatechange", function () {
|
||||
if (this.readyState === 4 && this.responseText) {
|
||||
commentBarrageConfig.barrageList = commentLinkFilter(JSON.parse(this.responseText).data);
|
||||
commentBarrageConfig.dom.innerHTML = "";
|
||||
}
|
||||
});
|
||||
xhr.open("POST", commentBarrageConfig.twikooUrl);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.send(data);
|
||||
|
||||
clearInterval(commentInterval);
|
||||
commentInterval = null;
|
||||
|
||||
commentInterval = setInterval(() => {
|
||||
if (commentBarrageConfig.barrageList.length && !hoverOnCommentBarrage) {
|
||||
popCommentBarrage(commentBarrageConfig.barrageList[commentBarrageConfig.barrageIndex]);
|
||||
commentBarrageConfig.barrageIndex += 1;
|
||||
commentBarrageConfig.barrageIndex %= commentBarrageConfig.barrageList.length;
|
||||
}
|
||||
if (
|
||||
commentBarrageConfig.barrageTimer.length >
|
||||
(commentBarrageConfig.barrageList.length > commentBarrageConfig.maxBarrage
|
||||
? commentBarrageConfig.maxBarrage
|
||||
: commentBarrageConfig.barrageList.length) &&
|
||||
!hoverOnCommentBarrage
|
||||
) {
|
||||
removeCommentBarrage(commentBarrageConfig.barrageTimer.shift());
|
||||
}
|
||||
}, commentBarrageConfig.barrageTime);
|
||||
}
|
||||
|
||||
function commentLinkFilter(data) {
|
||||
data.sort((a, b) => {
|
||||
return a.created - b.created;
|
||||
});
|
||||
let newData = [];
|
||||
data.forEach(item => {
|
||||
newData.push(...getCommentReplies(item));
|
||||
});
|
||||
return newData;
|
||||
}
|
||||
|
||||
function getCommentReplies(item) {
|
||||
if (item.replies) {
|
||||
let replies = [item];
|
||||
item.replies.forEach(item => {
|
||||
replies.push(...getCommentReplies(item));
|
||||
});
|
||||
return replies;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function popCommentBarrage(data) {
|
||||
let barrage = document.createElement("div");
|
||||
barrage.className = "comment-barrage-item";
|
||||
barrage.innerHTML = `
|
||||
<div class="barrageHead">
|
||||
<a class="barrageTitle ${
|
||||
data.mailMd5 === commentBarrageConfig.mailMd5 ? "barrageBloggerTitle" : ""
|
||||
}" href="javascript:anzhiyu.scrollTo('#post-comment')"">
|
||||
${data.mailMd5 === commentBarrageConfig.mailMd5 ? "博主" : "热评"}
|
||||
</a>
|
||||
<div class="barrageNick">${data.nick}</div>
|
||||
<img class="nolazyload barrageAvatar" src="https://cravatar.cn/avatar/${data.mailMd5}"/>
|
||||
<a class="comment-barrage-close" href="javascript:anzhiyu.switchCommentBarrage()"><i class="anzhiyufont anzhiyu-icon-xmark"></i></a>
|
||||
</div>
|
||||
<anzhiyu class="barrageContent" onClick="window.location.hash = '${data.id}'">
|
||||
${data.comment}
|
||||
</anzhiyu>
|
||||
`;
|
||||
|
||||
// 获取anzhiyu标签内的所有pre元素
|
||||
let anzhiyuPres = barrage.querySelectorAll("anzhiyu pre");
|
||||
|
||||
// 遍历每个pre元素,将其替换为"【代码】"
|
||||
anzhiyuPres.forEach(pre => {
|
||||
let codePlaceholder = document.createElement("span");
|
||||
codePlaceholder.innerText = "【代码】";
|
||||
pre.parentNode.replaceChild(codePlaceholder, pre);
|
||||
});
|
||||
|
||||
// 获取anzhiyu标签内的所有图片元素
|
||||
let anzhiyuImages = barrage.querySelectorAll("anzhiyu img");
|
||||
|
||||
// 遍历每个图片元素,将其替换为"【图片】",但排除带有class=tk-owo-emotion的图片
|
||||
anzhiyuImages.forEach(image => {
|
||||
if (!image.classList.contains("tk-owo-emotion")) {
|
||||
image.style.display = "none"; // 隐藏图片
|
||||
let placeholder = document.createElement("span");
|
||||
placeholder.innerText = "【图片】";
|
||||
image.parentNode.replaceChild(placeholder, image);
|
||||
}
|
||||
});
|
||||
commentBarrageConfig.barrageTimer.push(barrage);
|
||||
commentBarrageConfig.dom.append(barrage);
|
||||
}
|
||||
|
||||
function removeCommentBarrage(barrage) {
|
||||
barrage.className = "comment-barrage-item out";
|
||||
|
||||
setTimeout(() => {
|
||||
if (commentBarrageConfig.dom && commentBarrageConfig.dom.contains(barrage)) {
|
||||
commentBarrageConfig.dom.removeChild(barrage);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// 自动隐藏
|
||||
const commentEntryCallback = entries => {
|
||||
const commentBarrage = document.querySelector(".comment-barrage");
|
||||
const postComment = document.getElementById("post-comment");
|
||||
|
||||
entries.forEach(entry => {
|
||||
if (postComment && commentBarrage && document.body.clientWidth > 768) {
|
||||
commentBarrage.style.bottom = entry.isIntersecting ? `-${commentBarrageConfig.maxBarrage * 200}px` : "0";
|
||||
}
|
||||
});
|
||||
};
|
||||
// 创建IntersectionObserver实例
|
||||
const observer = new IntersectionObserver(commentEntryCallback, {
|
||||
root: null,
|
||||
rootMargin: "0px",
|
||||
threshold: 0,
|
||||
});
|
||||
// 监视目标元素
|
||||
const postCommentTarget = document.getElementById("post-comment");
|
||||
if (postCommentTarget) {
|
||||
observer.observe(postCommentTarget);
|
||||
}
|
||||
|
||||
initCommentBarrage();
|
||||
|
||||
if (localStorage.getItem("commentBarrageSwitch") !== "false") {
|
||||
document.querySelector(".comment-barrage").style.display = "flex";
|
||||
document.querySelector(".menu-commentBarrage-text").textContent = "关闭热评";
|
||||
} else {
|
||||
document.querySelector(".comment-barrage").style.display = "none";
|
||||
document.querySelector(".menu-commentBarrage-text").textContent = "显示热评";
|
||||
}
|
||||
|
||||
document.addEventListener("pjax:send", function () {
|
||||
clearInterval(commentInterval);
|
||||
});
|
||||
}
|
||||
271
themes/anzhiyu/source/js/anzhiyu/people.js
Normal file
271
themes/anzhiyu/source/js/anzhiyu/people.js
Normal file
@@ -0,0 +1,271 @@
|
||||
"use strict";
|
||||
function _toConsumableArray(e) {
|
||||
return _arrayWithoutHoles(e) || _iterableToArray(e) || _unsupportedIterableToArray(e) || _nonIterableSpread();
|
||||
}
|
||||
|
||||
function _nonIterableSpread() {
|
||||
throw new TypeError(
|
||||
"Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
|
||||
);
|
||||
}
|
||||
|
||||
function _unsupportedIterableToArray(e, r) {
|
||||
if (e) {
|
||||
if ("string" == typeof e) return _arrayLikeToArray(e, r);
|
||||
var t = Object.prototype.toString.call(e).slice(8, -1);
|
||||
return (
|
||||
"Object" === t && e.constructor && (t = e.constructor.name),
|
||||
"Map" === t || "Set" === t
|
||||
? Array.from(e)
|
||||
: "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t)
|
||||
? _arrayLikeToArray(e, r)
|
||||
: void 0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function _iterableToArray(e) {
|
||||
if (("undefined" != typeof Symbol && null != e[Symbol.iterator]) || null != e["@@iterator"]) return Array.from(e);
|
||||
}
|
||||
|
||||
function _arrayWithoutHoles(e) {
|
||||
if (Array.isArray(e)) return _arrayLikeToArray(e);
|
||||
}
|
||||
|
||||
function _arrayLikeToArray(e, r) {
|
||||
(null == r || r > e.length) && (r = e.length);
|
||||
for (var t = 0, a = new Array(r); t < r; t++) a[t] = e[t];
|
||||
return a;
|
||||
}
|
||||
|
||||
function _classCallCheck(e, r) {
|
||||
if (!(e instanceof r)) throw new TypeError("Cannot call a class as a function");
|
||||
}
|
||||
|
||||
function _defineProperties(e, r) {
|
||||
for (var t = 0; t < r.length; t++) {
|
||||
var a = r[t];
|
||||
(a.enumerable = a.enumerable || !1),
|
||||
(a.configurable = !0),
|
||||
"value" in a && (a.writable = !0),
|
||||
Object.defineProperty(e, a.key, a);
|
||||
}
|
||||
}
|
||||
|
||||
function _createClass(e, r, t) {
|
||||
return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), e;
|
||||
}
|
||||
var peopleConfig = {
|
||||
src: GLOBAL_CONFIG.peoplecanvas.img,
|
||||
rows: 15,
|
||||
cols: 7,
|
||||
},
|
||||
randomRange = function (e, r) {
|
||||
return e + Math.random() * (r - e);
|
||||
},
|
||||
randomIndex = function (e) {
|
||||
return 0 | randomRange(0, e.length);
|
||||
},
|
||||
removeFromArray = function (e, r) {
|
||||
return e.splice(r, 1)[0];
|
||||
},
|
||||
removeItemFromArray = function (e, r) {
|
||||
return removeFromArray(e, e.indexOf(r));
|
||||
},
|
||||
removeRandomFromArray = function (e) {
|
||||
return removeFromArray(e, randomIndex(e));
|
||||
},
|
||||
getRandomFromArray = function (e) {
|
||||
return e[0 | randomIndex(e)];
|
||||
},
|
||||
resetPeep = function (e) {
|
||||
var r,
|
||||
t,
|
||||
a = e.stage,
|
||||
n = e.peep,
|
||||
o = 0.5 < Math.random() ? 1 : -1,
|
||||
i = 100 - 250 * gsap.parseEase("power2.in")(Math.random()),
|
||||
s = a.height - n.height + i;
|
||||
return (
|
||||
1 == o ? ((r = -n.width), (t = a.width), (n.scaleX = 1)) : ((r = a.width + n.width), (t = 0), (n.scaleX = -1)),
|
||||
(n.x = r),
|
||||
(n.y = s),
|
||||
{
|
||||
startX: r,
|
||||
startY: (n.anchorY = s),
|
||||
endX: t,
|
||||
}
|
||||
);
|
||||
},
|
||||
normalWalk = function (e) {
|
||||
var r = e.peep,
|
||||
t = e.props,
|
||||
a = (t.startX, t.startY),
|
||||
n = t.endX,
|
||||
o = gsap.timeline();
|
||||
return (
|
||||
o.timeScale(randomRange(0.5, 1.5)),
|
||||
o.to(
|
||||
r,
|
||||
{
|
||||
duration: 10,
|
||||
x: n,
|
||||
ease: "none",
|
||||
},
|
||||
0
|
||||
),
|
||||
o.to(
|
||||
r,
|
||||
{
|
||||
duration: 0.25,
|
||||
repeat: 40,
|
||||
yoyo: !0,
|
||||
y: a - 10,
|
||||
},
|
||||
0
|
||||
),
|
||||
o
|
||||
);
|
||||
},
|
||||
walks = [normalWalk],
|
||||
Peep = (function () {
|
||||
function a(e) {
|
||||
var r = e.image,
|
||||
t = e.rect;
|
||||
_classCallCheck(this, a),
|
||||
(this.image = r),
|
||||
this.setRect(t),
|
||||
(this.x = 0),
|
||||
(this.y = 0),
|
||||
(this.anchorY = 0),
|
||||
(this.scaleX = 1),
|
||||
(this.walk = null);
|
||||
}
|
||||
return (
|
||||
_createClass(a, [
|
||||
{
|
||||
key: "setRect",
|
||||
value: function (e) {
|
||||
(this.rect = e),
|
||||
(this.width = e[2]),
|
||||
(this.height = e[3]),
|
||||
(this.drawArgs = [this.image].concat(_toConsumableArray(e), [0, 0, this.width, this.height]));
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "render",
|
||||
value: function (e) {
|
||||
e.save(),
|
||||
e.translate(this.x, this.y),
|
||||
e.scale(this.scaleX, 1),
|
||||
e.drawImage.apply(e, _toConsumableArray(this.drawArgs)),
|
||||
e.restore();
|
||||
},
|
||||
},
|
||||
]),
|
||||
a
|
||||
);
|
||||
})(),
|
||||
img = document.createElement("img");
|
||||
(img.onload = init), (img.src = peopleConfig.src);
|
||||
let peoplecanvasEl = document.getElementById("peoplecanvas");
|
||||
|
||||
let ctx = peoplecanvasEl ? peoplecanvasEl.getContext("2d") : undefined,
|
||||
stage = {
|
||||
width: 0,
|
||||
height: 0,
|
||||
},
|
||||
allPeeps = [],
|
||||
availablePeeps = [],
|
||||
crowd = [];
|
||||
|
||||
function init() {
|
||||
if (!peoplecanvasEl) return;
|
||||
createPeeps(), resize(), gsap.ticker.add(render), window.addEventListener("resize", resize);
|
||||
}
|
||||
document.addEventListener("pjax:success", e => {
|
||||
peoplecanvasEl = document.getElementById("peoplecanvas");
|
||||
if (peoplecanvasEl) {
|
||||
(ctx = peoplecanvasEl ? peoplecanvasEl.getContext("2d") : undefined), window.removeEventListener("resize", resize);
|
||||
gsap.ticker.remove(render);
|
||||
setTimeout(() => {
|
||||
if (!peoplecanvasEl) return;
|
||||
resize(), gsap.ticker.add(render), window.addEventListener("resize", resize);
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
|
||||
function createPeeps() {
|
||||
for (
|
||||
var e = peopleConfig.rows,
|
||||
r = peopleConfig.cols,
|
||||
t = e * r,
|
||||
a = img.naturalWidth / e,
|
||||
n = img.naturalHeight / r,
|
||||
o = 0;
|
||||
o < t;
|
||||
o++
|
||||
)
|
||||
allPeeps.push(
|
||||
new Peep({
|
||||
image: img,
|
||||
rect: [(o % e) * a, ((o / e) | 0) * n, a, n],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function resize() {
|
||||
if (peoplecanvasEl && peoplecanvasEl.clientWidth != 0) {
|
||||
(stage.width = peoplecanvasEl.clientWidth),
|
||||
(stage.height = peoplecanvasEl.clientHeight),
|
||||
(peoplecanvasEl.width = stage.width * devicePixelRatio),
|
||||
(peoplecanvasEl.height = stage.height * devicePixelRatio),
|
||||
crowd.forEach(function (e) {
|
||||
e.walk.kill();
|
||||
}),
|
||||
(crowd.length = 0),
|
||||
(availablePeeps.length = 0),
|
||||
availablePeeps.push.apply(availablePeeps, allPeeps),
|
||||
initCrowd();
|
||||
}
|
||||
}
|
||||
|
||||
function initCrowd() {
|
||||
for (; availablePeeps.length; ) addPeepToCrowd().walk.progress(Math.random());
|
||||
}
|
||||
|
||||
function addPeepToCrowd() {
|
||||
var e = removeRandomFromArray(availablePeeps),
|
||||
r = getRandomFromArray(walks)({
|
||||
peep: e,
|
||||
props: resetPeep({
|
||||
peep: e,
|
||||
stage: stage,
|
||||
}),
|
||||
}).eventCallback("onComplete", function () {
|
||||
removePeepFromCrowd(e), addPeepToCrowd();
|
||||
});
|
||||
return (
|
||||
(e.walk = r),
|
||||
crowd.push(e),
|
||||
crowd.sort(function (e, r) {
|
||||
return e.anchorY - r.anchorY;
|
||||
}),
|
||||
e
|
||||
);
|
||||
}
|
||||
|
||||
function removePeepFromCrowd(e) {
|
||||
removeItemFromArray(crowd, e), availablePeeps.push(e);
|
||||
}
|
||||
|
||||
function render() {
|
||||
if (!peoplecanvasEl) return;
|
||||
(peoplecanvasEl.width = peoplecanvasEl.width),
|
||||
ctx.save(),
|
||||
ctx.scale(devicePixelRatio, devicePixelRatio),
|
||||
crowd.forEach(function (e) {
|
||||
e.render(ctx);
|
||||
}),
|
||||
ctx.restore();
|
||||
}
|
||||
215
themes/anzhiyu/source/js/anzhiyu/random_friends_post.js
Normal file
215
themes/anzhiyu/source/js/anzhiyu/random_friends_post.js
Normal file
@@ -0,0 +1,215 @@
|
||||
var fdata = {
|
||||
apiurl: GLOBAL_CONFIG.friends_vue_info.apiurl,
|
||||
defaultFish: 100,
|
||||
hungryFish: 100,
|
||||
};
|
||||
//可通过 var fdataUser 替换默认值
|
||||
if (typeof fdataUser !== "undefined") {
|
||||
for (var key in fdataUser) {
|
||||
if (fdataUser[key]) {
|
||||
fdata[key] = fdataUser[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
var randomPostTimes = 0;
|
||||
var randomPostWorking = false;
|
||||
var randomPostTips = [
|
||||
"钓到了绝世好文!",
|
||||
"在河边打了个喷嚏,吓跑了",
|
||||
"你和小伙伴抢夺着",
|
||||
"你击败了巨龙,在巢穴中发现了",
|
||||
"挖掘秦始皇坟时找到了",
|
||||
"在路边闲逛的时候随手买了一个",
|
||||
"从学校班主任那拿来了孩子上课偷偷看的",
|
||||
"你的同桌无情的从你的语文书中撕下了那篇你最喜欢的",
|
||||
"考古学家近日发现了",
|
||||
"外星人降临地球学习地球文化,落地时被你塞了",
|
||||
"从图书馆顶层的隐秘角落里发现了闪着金光的",
|
||||
"徒弟修炼走火入魔,为师立刻掏出了",
|
||||
"在大山中唱山歌,隔壁的阿妹跑来了,带着",
|
||||
"隔壁家的孩子数学考了满分,都是因为看了",
|
||||
"隔壁家的孩子英语考了满分,都是因为看了",
|
||||
"小米研发了全新一代MIX手机,据说灵感",
|
||||
"修炼渡劫成功,还好提前看了",
|
||||
"库克坐上了苹果CEO的宝座,因为他面试的时候看了",
|
||||
"阿里巴巴大喊芝麻开门,映入眼帘的就是",
|
||||
"师傅说练武要先炼心,然后让我好生研读",
|
||||
"科考队在南极大陆发现了被冰封的",
|
||||
"飞机窗户似乎被一张纸糊上了,仔细一看是",
|
||||
"历史上满写的仁义道德四个字,透过字缝里却全是",
|
||||
"十几年前的录音机似乎还能够使用,插上电发现正在播的是",
|
||||
"新版语文书拟增加一篇熟读并背诵的",
|
||||
"经调查,99%的受访者都没有背诵过",
|
||||
"今年的高考满分作文是",
|
||||
"唐僧揭开了佛祖压在五指山上的",
|
||||
"科学家发现能够解决衰老的秘密,就是每日研读",
|
||||
"英特尔发布了全新的至强处理器,其芯片的制造原理都是",
|
||||
"新的iPhone产能很足,新的进货渠道是",
|
||||
"今年亩产突破了八千万斤,多亏了",
|
||||
"陆隐一统天上宗,在无数祖境高手的目光下宣读了",
|
||||
"黑钻风跟白钻风说道,吃了唐僧肉能长生不老,他知道是因为看了",
|
||||
"上卫生间没带纸,直接提裤跑路也不愿意玷污手中",
|
||||
"种下一篇文章就会产生很多很多文章,我种下了",
|
||||
"三十年河东,三十年河西,莫欺我没有看过",
|
||||
"踏破铁血无觅处,得来全靠",
|
||||
"今日双色球中了两千万,预测全靠",
|
||||
"因为卷子上没写名字,老师罚抄",
|
||||
"为了抗议世间的不公,割破手指写下了",
|
||||
"在艺术大街上被贴满了相同的纸,走近一看是",
|
||||
"这区区迷阵岂能难得住我?其实能走出来多亏了",
|
||||
"今日被一篇文章顶上了微博热搜,它是",
|
||||
"你送给乞丐一个暴富秘籍,它是",
|
||||
"UZI一个走A拿下五杀,在事后采访时说他当时回想起了",
|
||||
"科学家解刨了第一个感染丧尸病毒的人,发现丧尸抗体存在于",
|
||||
"如果你有梦想的话,就要努力去看",
|
||||
"决定我们成为什么样人的,不是我们的能力,而是是否看过",
|
||||
"有信心不一定会成功,没信心就去看",
|
||||
"你真正是谁并不重要,重要的是你看没看过",
|
||||
"玄天境重要的是锻体,为师赠你此书,好好修炼去吧,这是",
|
||||
"上百祖境高手在天威湖大战三天三夜为了抢夺",
|
||||
"这化仙池水乃上古真仙对后人的考校,要求熟读并背诵",
|
||||
"庆氏三千年根基差点竟被你小子毁于一旦,能够被我拯救全是因为我看了",
|
||||
"我就是神奇宝贝大师!我这只皮卡丘可是",
|
||||
"我就是神奇宝贝大师!我这只小火龙可是",
|
||||
"我就是神奇宝贝大师!我这只可达鸭可是",
|
||||
"我就是神奇宝贝大师!我这只杰尼龟可是",
|
||||
"上古遗迹中写道,只要习得此书,便得成功。你定睛一看,原来是",
|
||||
"奶奶的,玩阴的是吧,我就是双料特工代号穿山甲,",
|
||||
"你的背景太假了,我的就逼真多了,学到这个技术全是因为看了",
|
||||
"我是云南的,云南怒江的,怒江芦水市,芦水市六库,六库傈僳族,傈僳族是",
|
||||
"我真的栓Q了,我真的会谢如果你看",
|
||||
"你已经习得退退退神功,接下来的心法已经被记录在",
|
||||
"人生无常大肠包小肠,小肠包住了",
|
||||
"你抽到了普通文章,它是",
|
||||
"你收到了稀有文章,它是",
|
||||
"你抽到了金色普通文章,它是",
|
||||
"你抽到了金色稀有文章,它是",
|
||||
"你抽到了传说文章!它是",
|
||||
"哇!金色传说!你抽到了金色传说文章,它是",
|
||||
"报告!侦察兵说在前往300米有一个男子在偷偷看一本书,上面赫然写着",
|
||||
"芷莲姑娘大摆擂台,谁若是能读完此书,便可娶了她。然后从背后掏出了",
|
||||
"请问你的梦想是什么?我的梦想是能读到",
|
||||
"读什么才能增智慧?当然是读",
|
||||
"纳兰嫣然掏出了退婚书,可是发现出门带错了,结果拿出了一本",
|
||||
"你要尽全力保护你的梦想。那些嘲笑你的人,他们必定会失败,他们想把你变成和他们一样的人。如果你有梦想的话,就要努力去读",
|
||||
"走人生的路就像爬山一样,看起来走了许多冤枉的路,崎岖的路,但终究需要读完",
|
||||
"游戏的规则就是这么的简单,你听懂了吗?管你听没听懂,快去看",
|
||||
];
|
||||
var randomPostClick = 0;
|
||||
function fetchRandomPost() {
|
||||
if (!document.getElementById("random-post")) return;
|
||||
if (randomPostWorking == false) {
|
||||
randomPostWorking = true;
|
||||
//获取旋转角度
|
||||
let randomRotate = randomPostTimes * 360;
|
||||
let randomPostTipsItem = randomPostTips[Math.floor(Math.random() * randomPostTips.length)];
|
||||
let randomPostLevel = "";
|
||||
if (randomPostTimes > 10000) {
|
||||
randomPostLevel = "愿者上钩";
|
||||
} else if (randomPostTimes > 1000) {
|
||||
randomPostLevel = "俯览天下";
|
||||
} else if (randomPostTimes > 1000) {
|
||||
randomPostLevel = "超越神了";
|
||||
} else if (randomPostTimes > 100) {
|
||||
randomPostLevel = "绝世渔夫";
|
||||
} else if (randomPostTimes > 75) {
|
||||
randomPostLevel = "钓鱼王者";
|
||||
} else if (randomPostTimes > 50) {
|
||||
randomPostLevel = "钓鱼宗师";
|
||||
} else if (randomPostTimes > 20) {
|
||||
randomPostLevel = "钓鱼专家";
|
||||
} else if (randomPostTimes > 5) {
|
||||
randomPostLevel = "钓鱼高手";
|
||||
} else {
|
||||
randomPostLevel = "钓鱼新手";
|
||||
}
|
||||
if (randomPostTimes >= 5) {
|
||||
document.getElementById("random-post").innerHTML =
|
||||
`钓鱼中... (Lv.` + randomPostTimes + ` 当前称号:` + randomPostLevel + `)`;
|
||||
} else {
|
||||
document.getElementById("random-post").innerHTML = `钓鱼中...`;
|
||||
}
|
||||
|
||||
let randomTime = randomNum(1000, 3000);
|
||||
|
||||
if (randomPostTimes == 0) {
|
||||
randomTime = 0;
|
||||
}
|
||||
|
||||
document.querySelector(".random-post-start").style.opacity = "0.2";
|
||||
document.querySelector(".random-post-start").style.transitionDuration = "0.3s";
|
||||
document.querySelector(".random-post-start").style.transform = "rotate(" + randomRotate + "deg)";
|
||||
|
||||
//判断是否饥饿
|
||||
if (
|
||||
document.getElementById("random-post") &&
|
||||
randomPostClick * fdata.hungryFish + fdata.defaultFish < randomPostTimes &&
|
||||
Math.round(Math.random()) == 0
|
||||
) {
|
||||
document.getElementById("random-post").innerHTML =
|
||||
"因为只钓鱼不吃鱼,过分饥饿导致本次钓鱼失败...(点击任意一篇钓鱼获得的文章即可恢复)";
|
||||
randomPostWorking = false;
|
||||
} else {
|
||||
var fetchUrl = fdata.apiurl + "randompost";
|
||||
fetch(fetchUrl)
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
var title = json.title;
|
||||
var link = json.link;
|
||||
var author = json.author;
|
||||
if (document.getElementById("random-post")) {
|
||||
window.setTimeout(function () {
|
||||
document.getElementById("random-post").innerHTML =
|
||||
randomPostTipsItem +
|
||||
`来自友链 <b>` +
|
||||
author +
|
||||
`</b> 的文章:<a class="random-friends-post" onclick="randomClickLink()" target="_blank" href="` +
|
||||
link +
|
||||
`" rel="external nofollow">` +
|
||||
title +
|
||||
`</a>`;
|
||||
randomPostTimes += 1;
|
||||
localStorage.setItem("randomPostTimes", randomPostTimes);
|
||||
document.querySelector(".random-post-start").style.opacity = "1";
|
||||
}, randomTime);
|
||||
}
|
||||
});
|
||||
randomPostWorking = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//初始化检查
|
||||
function initRandomPost() {
|
||||
// 获取已经存储的数据
|
||||
if (localStorage.randomPostTimes) {
|
||||
randomPostTimes = parseInt(localStorage.randomPostTimes);
|
||||
randomPostClick = parseInt(localStorage.randomPostClick);
|
||||
document.querySelector(".random-post-start").style.transitionDuration = "0.3s";
|
||||
document.querySelector(".random-post-start").style.transform = "rotate(" + 360 * randomPostTimes + "deg)";
|
||||
}
|
||||
fetchRandomPost();
|
||||
}
|
||||
|
||||
initRandomPost();
|
||||
|
||||
//添加点击统计
|
||||
function randomClickLink() {
|
||||
randomPostClick += 1;
|
||||
localStorage.setItem("randomPostClick", randomPostClick);
|
||||
}
|
||||
|
||||
// 生成随机数
|
||||
function randomNum(minNum, maxNum) {
|
||||
switch (arguments.length) {
|
||||
case 1:
|
||||
return parseInt(Math.random() * minNum + 1, 10);
|
||||
break;
|
||||
case 2:
|
||||
return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
479
themes/anzhiyu/source/js/anzhiyu/right_click_menu.js
Normal file
479
themes/anzhiyu/source/js/anzhiyu/right_click_menu.js
Normal file
@@ -0,0 +1,479 @@
|
||||
// 初始化函数
|
||||
rm = {};
|
||||
|
||||
//禁止图片与超链接拖拽
|
||||
let aElements = document.getElementsByTagName("a");
|
||||
for (let i = 0; i < aElements.length; i++) {
|
||||
aElements[i].setAttribute("draggable", "false");
|
||||
let imgElements = aElements[i].getElementsByTagName("img");
|
||||
for (let j = 0; j < imgElements.length; j++) {
|
||||
imgElements[j].setAttribute("draggable", "false");
|
||||
}
|
||||
}
|
||||
|
||||
// 显示菜单
|
||||
rm.showRightMenu = function (isTrue, x = 0, y = 0) {
|
||||
console.info(x, y);
|
||||
let rightMenu = document.getElementById("rightMenu");
|
||||
rightMenu.style.top = x + "px";
|
||||
rightMenu.style.left = y + "px";
|
||||
if (isTrue) {
|
||||
rightMenu.style.display = "block";
|
||||
stopMaskScroll();
|
||||
} else {
|
||||
rightMenu.style.display = "none";
|
||||
}
|
||||
};
|
||||
|
||||
// 隐藏菜单
|
||||
rm.hideRightMenu = function () {
|
||||
rm.showRightMenu(false);
|
||||
let rightMenuMask = document.querySelector("#rightmenu-mask");
|
||||
rightMenuMask.style.display = "none";
|
||||
};
|
||||
|
||||
// 尺寸
|
||||
let rmWidth = document.getElementById("rightMenu").offsetWidth;
|
||||
let rmHeight = document.getElementById("rightMenu").offsetHeight;
|
||||
|
||||
// 重新定义尺寸
|
||||
rm.reloadrmSize = function () {
|
||||
rightMenu.style.visibility = "hidden";
|
||||
rightMenu.style.display = "block";
|
||||
// 获取宽度和高度
|
||||
rmWidth = document.getElementById("rightMenu").offsetWidth;
|
||||
rmHeight = document.getElementById("rightMenu").offsetHeight;
|
||||
rightMenu.style.visibility = "visible";
|
||||
};
|
||||
|
||||
// 获取点击的href
|
||||
let domhref = "";
|
||||
let domImgSrc = "";
|
||||
let globalEvent = null;
|
||||
|
||||
var oncontextmenuFunction = function (event) {
|
||||
if (document.body.clientWidth > 768) {
|
||||
let pageX = event.clientX + 10; //加10是为了防止显示时鼠标遮在菜单上
|
||||
let pageY = event.clientY;
|
||||
|
||||
//其他额外菜单
|
||||
const $rightMenuOther = document.querySelector(".rightMenuOther");
|
||||
const $rightMenuPlugin = document.querySelector(".rightMenuPlugin");
|
||||
const $rightMenuCopyText = document.querySelector("#menu-copytext");
|
||||
const $rightMenuPasteText = document.querySelector("#menu-pastetext");
|
||||
const $rightMenuCommentText = document.querySelector("#menu-commenttext");
|
||||
const $rightMenuNewWindow = document.querySelector("#menu-newwindow");
|
||||
const $rightMenuNewWindowImg = document.querySelector("#menu-newwindowimg");
|
||||
const $rightMenuCopyLink = document.querySelector("#menu-copylink");
|
||||
const $rightMenuCopyImg = document.querySelector("#menu-copyimg");
|
||||
const $rightMenuDownloadImg = document.querySelector("#menu-downloadimg");
|
||||
const $rightMenuSearch = document.querySelector("#menu-search");
|
||||
const $rightMenuSearchBaidu = document.querySelector("#menu-searchBaidu");
|
||||
const $rightMenuMusicToggle = document.querySelector("#menu-music-toggle");
|
||||
const $rightMenuMusicBack = document.querySelector("#menu-music-back");
|
||||
const $rightMenuMusicForward = document.querySelector("#menu-music-forward");
|
||||
const $rightMenuMusicPlaylist = document.querySelector("#menu-music-playlist");
|
||||
const $rightMenuMusicCopyMusicName = document.querySelector("#menu-music-copyMusicName");
|
||||
|
||||
let href = event.target.href;
|
||||
let imgsrc = event.target.currentSrc;
|
||||
|
||||
// 判断模式 扩展模式为有事件
|
||||
let pluginMode = false;
|
||||
$rightMenuOther.style.display = "block";
|
||||
globalEvent = event;
|
||||
|
||||
// 检查是否需要复制 是否有选中文本
|
||||
if (selectTextNow && window.getSelection()) {
|
||||
pluginMode = true;
|
||||
$rightMenuCopyText.style.display = "block";
|
||||
$rightMenuCommentText.style.display = "block";
|
||||
$rightMenuSearch.style.display = "block";
|
||||
$rightMenuSearchBaidu.style.display = "block";
|
||||
} else {
|
||||
$rightMenuCopyText.style.display = "none";
|
||||
$rightMenuCommentText.style.display = "none";
|
||||
$rightMenuSearchBaidu.style.display = "none";
|
||||
$rightMenuSearch.style.display = "none";
|
||||
}
|
||||
|
||||
//检查是否右键点击了链接a标签
|
||||
if (href) {
|
||||
pluginMode = true;
|
||||
$rightMenuNewWindow.style.display = "block";
|
||||
$rightMenuCopyLink.style.display = "block";
|
||||
domhref = href;
|
||||
} else {
|
||||
$rightMenuNewWindow.style.display = "none";
|
||||
$rightMenuCopyLink.style.display = "none";
|
||||
}
|
||||
|
||||
//检查是否需要复制图片
|
||||
if (imgsrc) {
|
||||
pluginMode = true;
|
||||
$rightMenuCopyImg.style.display = "block";
|
||||
$rightMenuDownloadImg.style.display = "block";
|
||||
$rightMenuNewWindowImg.style.display = "block";
|
||||
document.getElementById("rightMenu").style.width = "12rem";
|
||||
domImgSrc = imgsrc;
|
||||
} else {
|
||||
$rightMenuCopyImg.style.display = "none";
|
||||
$rightMenuDownloadImg.style.display = "none";
|
||||
$rightMenuNewWindowImg.style.display = "none";
|
||||
}
|
||||
|
||||
// 判断是否为输入框
|
||||
if (event.target.tagName.toLowerCase() === "input" || event.target.tagName.toLowerCase() === "textarea") {
|
||||
pluginMode = true;
|
||||
$rightMenuPasteText.style.display = "block";
|
||||
} else {
|
||||
$rightMenuPasteText.style.display = "none";
|
||||
}
|
||||
const navMusicEl = document.querySelector("#nav-music");
|
||||
//判断是否是音乐
|
||||
if (navMusicEl && navMusicEl.contains(event.target)) {
|
||||
pluginMode = true;
|
||||
$rightMenuMusicToggle.style.display = "block";
|
||||
$rightMenuMusicBack.style.display = "block";
|
||||
$rightMenuMusicForward.style.display = "block";
|
||||
$rightMenuMusicPlaylist.style.display = "block";
|
||||
$rightMenuMusicCopyMusicName.style.display = "block";
|
||||
} else {
|
||||
$rightMenuMusicToggle.style.display = "none";
|
||||
$rightMenuMusicBack.style.display = "none";
|
||||
$rightMenuMusicForward.style.display = "none";
|
||||
$rightMenuMusicPlaylist.style.display = "none";
|
||||
$rightMenuMusicCopyMusicName.style.display = "none";
|
||||
}
|
||||
|
||||
// 如果不是扩展模式则隐藏扩展模块
|
||||
if (pluginMode) {
|
||||
$rightMenuOther.style.display = "none";
|
||||
$rightMenuPlugin.style.display = "block";
|
||||
} else {
|
||||
$rightMenuPlugin.style.display = "none";
|
||||
}
|
||||
|
||||
rm.reloadrmSize();
|
||||
|
||||
// 鼠标默认显示在鼠标右下方,当鼠标靠右或靠下时,将菜单显示在鼠标左方\上方
|
||||
if (pageX + rmWidth > window.innerWidth) {
|
||||
pageX -= rmWidth + 10;
|
||||
}
|
||||
if (pageY + rmHeight > window.innerHeight) {
|
||||
pageY -= pageY + rmHeight - window.innerHeight;
|
||||
}
|
||||
|
||||
rm.showRightMenu(true, pageY, pageX);
|
||||
document.getElementById("rightmenu-mask").style.display = "flex";
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 监听右键初始化
|
||||
window.oncontextmenu = oncontextmenuFunction;
|
||||
|
||||
// 下载图片状态
|
||||
rm.downloadimging = false;
|
||||
|
||||
// 复制图片到剪贴板
|
||||
rm.writeClipImg = function (imgsrc) {
|
||||
console.log("按下复制");
|
||||
rm.hideRightMenu();
|
||||
anzhiyu.snackbarShow("正在下载中,请稍后", false, 10000);
|
||||
if (rm.downloadimging == false) {
|
||||
rm.downloadimging = true;
|
||||
setTimeout(function () {
|
||||
copyImage(imgsrc);
|
||||
anzhiyu.snackbarShow("复制成功!图片已添加盲水印,请遵守版权协议");
|
||||
rm.downloadimging = false;
|
||||
}, "10000");
|
||||
}
|
||||
};
|
||||
|
||||
function imageToBlob(imageURL) {
|
||||
const img = new Image();
|
||||
const c = document.createElement("canvas");
|
||||
const ctx = c.getContext("2d");
|
||||
img.crossOrigin = "";
|
||||
img.src = imageURL;
|
||||
return new Promise(resolve => {
|
||||
img.onload = function () {
|
||||
c.width = this.naturalWidth;
|
||||
c.height = this.naturalHeight;
|
||||
ctx.drawImage(this, 0, 0);
|
||||
c.toBlob(
|
||||
blob => {
|
||||
// here the image is a blob
|
||||
resolve(blob);
|
||||
},
|
||||
"image/png",
|
||||
0.75
|
||||
);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function copyImage(imageURL) {
|
||||
const blob = await imageToBlob(imageURL);
|
||||
const item = new ClipboardItem({ "image/png": blob });
|
||||
navigator.clipboard.write([item]);
|
||||
}
|
||||
|
||||
rm.copyUrl = function (id) {
|
||||
const input = document.createElement("input"); // Create a new <input> element
|
||||
input.id = "copyVal"; // Set the id of the new element to "copyVal"
|
||||
document.body.appendChild(input); // Append the new element to the end of the <body> element
|
||||
|
||||
const text = id;
|
||||
input.value = text;
|
||||
input.select();
|
||||
input.setSelectionRange(0, input.value.length);
|
||||
document.execCommand("copy");
|
||||
|
||||
input.remove(); // Remove the <input> element from the DOM
|
||||
};
|
||||
|
||||
function stopMaskScroll() {
|
||||
if (document.getElementById("rightmenu-mask")) {
|
||||
let xscroll = document.getElementById("rightmenu-mask");
|
||||
xscroll.addEventListener(
|
||||
"mousewheel",
|
||||
function (e) {
|
||||
//阻止浏览器默认方法
|
||||
rm.hideRightMenu();
|
||||
// e.preventDefault();
|
||||
},
|
||||
{ passive: true }
|
||||
);
|
||||
}
|
||||
if (document.getElementById("rightMenu")) {
|
||||
let xscroll = document.getElementById("rightMenu");
|
||||
xscroll.addEventListener(
|
||||
"mousewheel",
|
||||
function (e) {
|
||||
//阻止浏览器默认方法
|
||||
rm.hideRightMenu();
|
||||
// e.preventDefault();
|
||||
},
|
||||
{ passive: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
rm.rightmenuCopyText = function (txt) {
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(txt);
|
||||
}
|
||||
rm.hideRightMenu();
|
||||
};
|
||||
|
||||
rm.copyPageUrl = function (url) {
|
||||
if (!url) {
|
||||
url = window.location.href;
|
||||
}
|
||||
rm.copyUrl(url);
|
||||
anzhiyu.snackbarShow("复制链接地址成功", false, 2000);
|
||||
rm.hideRightMenu();
|
||||
};
|
||||
|
||||
// 复制当前选中文本
|
||||
var selectTextNow = "";
|
||||
document.onmouseup = document.ondblclick = selceText;
|
||||
|
||||
function selceText() {
|
||||
var txt;
|
||||
if (document.selection) {
|
||||
txt = document.selection.createRange().text;
|
||||
} else {
|
||||
txt = window.getSelection().toString();
|
||||
}
|
||||
selectTextNow = txt !== "" ? txt : "";
|
||||
}
|
||||
|
||||
// 读取剪切板
|
||||
rm.readClipboard = function () {
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.readText().then(clipText => rm.insertAtCaret(globalEvent.target, clipText));
|
||||
}
|
||||
};
|
||||
|
||||
// 粘贴文本到焦点
|
||||
rm.insertAtCaret = function (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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//粘贴文本
|
||||
rm.pasteText = function () {
|
||||
const result = rm.readClipboard() || "";
|
||||
rm.hideRightMenu();
|
||||
};
|
||||
|
||||
//引用到评论
|
||||
rm.rightMenuCommentText = function (txt) {
|
||||
rm.hideRightMenu();
|
||||
const postCommentDom = document.getElementById("post-comment");
|
||||
var domTop = postCommentDom.offsetTop;
|
||||
window.scrollTo(0, domTop - 80);
|
||||
if (txt == "undefined" || txt == "null") txt = "好棒!";
|
||||
function setText() {
|
||||
setTimeout(() => {
|
||||
var input = document.getElementsByClassName("el-textarea__inner")[0];
|
||||
if (!input) setText();
|
||||
let evt = document.createEvent("HTMLEvents");
|
||||
evt.initEvent("input", true, true);
|
||||
let inputValue = replaceAll(txt, "\n", "\n> ");
|
||||
input.value = "> " + inputValue + "\n\n";
|
||||
input.dispatchEvent(evt);
|
||||
input.focus();
|
||||
input.setSelectionRange(-1, -1);
|
||||
if (document.getElementById("comment-tips")) {
|
||||
document.getElementById("comment-tips").classList.add("show");
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
setText();
|
||||
};
|
||||
|
||||
//替换所有内容
|
||||
function replaceAll(string, search, replace) {
|
||||
return string.split(search).join(replace);
|
||||
}
|
||||
|
||||
// 百度搜索
|
||||
rm.searchBaidu = function () {
|
||||
anzhiyu.snackbarShow("即将跳转到百度搜索", false, 2000);
|
||||
setTimeout(function () {
|
||||
window.open("https://www.baidu.com/s?wd=" + selectTextNow);
|
||||
}, "2000");
|
||||
rm.hideRightMenu();
|
||||
};
|
||||
|
||||
//分享链接
|
||||
rm.copyLink = function () {
|
||||
rm.rightmenuCopyText(domhref);
|
||||
anzhiyu.snackbarShow("已复制链接地址");
|
||||
};
|
||||
|
||||
function addRightMenuClickEvent() {
|
||||
// 添加点击事件
|
||||
document.getElementById("menu-backward").addEventListener("click", function () {
|
||||
window.history.back();
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
document.getElementById("menu-forward").addEventListener("click", function () {
|
||||
window.history.forward();
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
document.getElementById("menu-refresh").addEventListener("click", function () {
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
document.getElementById("menu-top").addEventListener("click", function () {
|
||||
anzhiyu.scrollToDest(0, 500);
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
document.getElementById("menu-translate").addEventListener("click", function () {
|
||||
window.translateFn.translatePage();
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
const menuLinks = document.querySelectorAll(".menu-link");
|
||||
menuLinks.forEach(function (link) {
|
||||
link.addEventListener("click", rm.hideRightMenu);
|
||||
});
|
||||
|
||||
document.getElementById("menu-home") &&
|
||||
document.getElementById("menu-home").addEventListener("click", function () {
|
||||
window.location.href = window.location.origin;
|
||||
});
|
||||
|
||||
document.getElementById("menu-randomPost").addEventListener("click", function () {
|
||||
toRandomPost();
|
||||
});
|
||||
|
||||
document.getElementById("menu-commentBarrage").addEventListener("click", anzhiyu.switchCommentBarrage);
|
||||
|
||||
document.getElementById("rightmenu-mask").addEventListener("click", rm.hideRightMenu);
|
||||
|
||||
document.getElementById("rightmenu-mask").addEventListener("contextmenu", function (event) {
|
||||
rm.hideRightMenu();
|
||||
event.preventDefault(); // Prevent the default context menu from appearing
|
||||
});
|
||||
|
||||
document.getElementById("menu-copy").addEventListener("click", () => {
|
||||
rm.copyPageUrl();
|
||||
});
|
||||
|
||||
document.getElementById("menu-pastetext").addEventListener("click", rm.pasteText);
|
||||
|
||||
document.getElementById("menu-copytext").addEventListener("click", function () {
|
||||
rm.rightmenuCopyText(selectTextNow);
|
||||
const copyright = GLOBAL_CONFIG.copyright;
|
||||
if (copyright.copy) {
|
||||
anzhiyu.snackbarShow(copyright.languages.copySuccess);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("menu-commenttext").addEventListener("click", function () {
|
||||
rm.rightMenuCommentText(selectTextNow);
|
||||
});
|
||||
|
||||
document.getElementById("menu-newwindow").addEventListener("click", function () {
|
||||
window.open(domhref, "_blank");
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
document.getElementById("menu-copylink").addEventListener("click", rm.copyLink);
|
||||
|
||||
document.getElementById("menu-downloadimg").addEventListener("click", function () {
|
||||
anzhiyu.downloadImage(domImgSrc, "anzhiyu");
|
||||
});
|
||||
|
||||
document.getElementById("menu-newwindowimg").addEventListener("click", function () {
|
||||
window.open(domImgSrc, "_blank");
|
||||
rm.hideRightMenu();
|
||||
});
|
||||
|
||||
document.getElementById("menu-copyimg").addEventListener("click", function () {
|
||||
rm.writeClipImg(domImgSrc);
|
||||
});
|
||||
|
||||
document.getElementById("menu-searchBaidu").addEventListener("click", rm.searchBaidu);
|
||||
|
||||
//音乐
|
||||
document.getElementById("menu-music-toggle").addEventListener("click", anzhiyu.musicToggle);
|
||||
|
||||
document.getElementById("menu-music-back").addEventListener("click", anzhiyu.musicSkipBack);
|
||||
|
||||
document.getElementById("menu-music-forward").addEventListener("click", anzhiyu.musicSkipForward);
|
||||
|
||||
document.getElementById("menu-music-copyMusicName").addEventListener("click", function () {
|
||||
rm.rightmenuCopyText(anzhiyu.musicGetName());
|
||||
anzhiyu.snackbarShow("复制歌曲名称成功", false, 3000);
|
||||
});
|
||||
}
|
||||
|
||||
addRightMenuClickEvent();
|
||||
1813
themes/anzhiyu/source/js/main.js
Normal file
1813
themes/anzhiyu/source/js/main.js
Normal file
File diff suppressed because it is too large
Load Diff
192
themes/anzhiyu/source/js/search/algolia.js
Normal file
192
themes/anzhiyu/source/js/search/algolia.js
Normal file
@@ -0,0 +1,192 @@
|
||||
window.addEventListener("load", () => {
|
||||
const $searchMask = document.getElementById("search-mask");
|
||||
const $searchDialog = document.querySelector("#algolia-search .search-dialog");
|
||||
|
||||
const openSearch = () => {
|
||||
anzhiyu.animateIn($searchMask, "to_show 0.5s");
|
||||
$searchDialog.style.display = "block";
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
|
||||
}, 100);
|
||||
|
||||
// shortcut: ESC
|
||||
document.addEventListener("keydown", function f(event) {
|
||||
if (event.code === "Escape") {
|
||||
closeSearch();
|
||||
document.removeEventListener("keydown", f);
|
||||
}
|
||||
});
|
||||
|
||||
fixSafariHeight();
|
||||
window.addEventListener("resize", fixSafariHeight);
|
||||
};
|
||||
|
||||
// shortcut: shift+S
|
||||
if (anzhiyu_keyboard) {
|
||||
window.addEventListener("keydown", function (event) {
|
||||
if (event.keyCode == 83 && event.shiftKey) {
|
||||
console.info(selectTextNow);
|
||||
if (selectTextNow) {
|
||||
openSearch();
|
||||
const t = document.querySelector("#algolia-search-input > div > form > input");
|
||||
t.value = selectTextNow;
|
||||
t.dispatchEvent(new Event("input"));
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search-input > div > form > button.ais-SearchBox-submit").click();
|
||||
}, 64);
|
||||
} else {
|
||||
openSearch();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const closeSearch = () => {
|
||||
anzhiyu.animateOut($searchDialog, "search_close .5s");
|
||||
anzhiyu.animateOut($searchMask, "to_hide 0.5s");
|
||||
window.removeEventListener("resize", fixSafariHeight);
|
||||
};
|
||||
|
||||
// fix safari
|
||||
const fixSafariHeight = () => {
|
||||
if (window.innerWidth < 768) {
|
||||
$searchDialog.style.setProperty("--search-height", window.innerHeight + "px");
|
||||
}
|
||||
};
|
||||
|
||||
const searchClickFn = () => {
|
||||
anzhiyu.addEventListenerPjax(document.querySelector("#search-button > .search"), "click", openSearch);
|
||||
};
|
||||
|
||||
const searchFnOnce = () => {
|
||||
$searchMask.addEventListener("click", closeSearch);
|
||||
document.querySelector("#algolia-search .search-close-button").addEventListener("click", closeSearch);
|
||||
};
|
||||
|
||||
const algolia = GLOBAL_CONFIG.algolia;
|
||||
const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName;
|
||||
if (!isAlgoliaValid) {
|
||||
return console.error("Algolia setting is invalid!");
|
||||
}
|
||||
|
||||
const search = instantsearch({
|
||||
indexName: algolia.indexName,
|
||||
/* global algoliasearch */
|
||||
searchClient: algoliasearch(algolia.appId, algolia.apiKey),
|
||||
searchFunction(helper) {
|
||||
if (helper.state.query) {
|
||||
let innerLoading = '<i class="anzhiyufont anzhiyu-icon-spinner anzhiyu-spin"></i>';
|
||||
document.getElementById("algolia-hits").innerHTML = innerLoading;
|
||||
helper.search();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const configure = instantsearch.widgets.configure({
|
||||
hitsPerPage: algolia.hits.per_page ?? 5,
|
||||
});
|
||||
|
||||
const searchBox = instantsearch.widgets.searchBox({
|
||||
container: "#algolia-search-input",
|
||||
showReset: false,
|
||||
showSubmit: false,
|
||||
placeholder: algolia.languages.input_placeholder,
|
||||
showLoadingIndicator: true,
|
||||
searchOnEnterKeyPressOnly: true,
|
||||
searchAsYouType: false,
|
||||
});
|
||||
|
||||
const hits = instantsearch.widgets.hits({
|
||||
container: "#algolia-hits",
|
||||
templates: {
|
||||
item(data) {
|
||||
const link = data.permalink ? data.permalink : GLOBAL_CONFIG.root + data.path;
|
||||
const result = data._highlightResult;
|
||||
const loadingLogo = document.querySelector("#algolia-hits .anzhiyu-spin");
|
||||
if (loadingLogo) {
|
||||
loadingLogo.style.display = "none";
|
||||
}
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
|
||||
}, 200);
|
||||
return `
|
||||
<a href="${link}" class="algolia-hit-item-link">
|
||||
<span class="algolia-hits-item-title">${result.title.value || "no-title"}</span>
|
||||
</a>`;
|
||||
},
|
||||
empty: function (data) {
|
||||
const loadingLogo = document.querySelector("#algolia-hits .anzhiyu-spin");
|
||||
console.info(loadingLogo);
|
||||
if (loadingLogo) {
|
||||
loadingLogo.style.display = "none";
|
||||
}
|
||||
setTimeout(() => {
|
||||
document.querySelector("#algolia-search .ais-SearchBox-input").focus();
|
||||
}, 200);
|
||||
return (
|
||||
'<div id="algolia-hits-empty">' +
|
||||
GLOBAL_CONFIG.algolia.languages.hits_empty.replace(/\$\{query}/, data.query) +
|
||||
"</div>"
|
||||
);
|
||||
},
|
||||
},
|
||||
cssClasses: {
|
||||
item: "algolia-hit-item",
|
||||
},
|
||||
});
|
||||
|
||||
const stats = instantsearch.widgets.stats({
|
||||
container: "#algolia-info > .algolia-stats",
|
||||
templates: {
|
||||
text: function (data) {
|
||||
const stats = GLOBAL_CONFIG.algolia.languages.hits_stats
|
||||
.replace(/\$\{hits}/, data.nbHits)
|
||||
.replace(/\$\{time}/, data.processingTimeMS);
|
||||
return `<hr>${stats}`;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const powerBy = instantsearch.widgets.poweredBy({
|
||||
container: "#algolia-info > .algolia-poweredBy",
|
||||
});
|
||||
|
||||
const pagination = instantsearch.widgets.pagination({
|
||||
container: "#algolia-pagination",
|
||||
totalPages: algolia.hits.per_page ?? 5,
|
||||
templates: {
|
||||
first: '<i class="anzhiyufont anzhiyu-icon-angle-double-left"></i>',
|
||||
last: '<i class="anzhiyufont anzhiyu-icon-angle-double-right"></i>',
|
||||
previous: '<i class="anzhiyufont anzhiyu-icon-angle-left"></i>',
|
||||
next: '<i class="anzhiyufont anzhiyu-icon-angle-right"></i>',
|
||||
},
|
||||
scrollTo: false,
|
||||
showFirstLast: false,
|
||||
cssClasses: {
|
||||
root: "pagination",
|
||||
item: "pagination-item",
|
||||
link: "page-number",
|
||||
active: "current",
|
||||
disabled: "disabled-item",
|
||||
},
|
||||
});
|
||||
|
||||
search.addWidgets([configure, searchBox, hits, stats, powerBy, pagination]); // add the widgets to the instantsearch instance
|
||||
|
||||
search.start();
|
||||
|
||||
searchClickFn();
|
||||
searchFnOnce();
|
||||
|
||||
window.addEventListener("pjax:complete", () => {
|
||||
!anzhiyu.isHidden($searchMask) && closeSearch();
|
||||
searchClickFn();
|
||||
});
|
||||
|
||||
window.pjax &&
|
||||
search.on("render", () => {
|
||||
window.pjax.refresh(document.getElementById("algolia-hits"));
|
||||
});
|
||||
});
|
||||
270
themes/anzhiyu/source/js/search/local-search.js
Normal file
270
themes/anzhiyu/source/js/search/local-search.js
Normal file
@@ -0,0 +1,270 @@
|
||||
window.addEventListener("load", () => {
|
||||
let loadFlag = false;
|
||||
let dataObj = [];
|
||||
const $searchMask = document.getElementById("search-mask");
|
||||
|
||||
const openSearch = () => {
|
||||
const bodyStyle = document.body.style;
|
||||
bodyStyle.width = "100%";
|
||||
bodyStyle.overflow = "hidden";
|
||||
anzhiyu.animateIn($searchMask, "to_show 0.5s");
|
||||
anzhiyu.animateIn(document.querySelector("#local-search .search-dialog"), "titleScale 0.5s");
|
||||
setTimeout(() => {
|
||||
document.querySelector("#local-search-input input").focus();
|
||||
}, 100);
|
||||
if (!loadFlag) {
|
||||
search();
|
||||
loadFlag = true;
|
||||
}
|
||||
// shortcut: ESC
|
||||
document.addEventListener("keydown", function f(event) {
|
||||
if (event.code === "Escape") {
|
||||
closeSearch();
|
||||
document.removeEventListener("keydown", f);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const closeSearch = () => {
|
||||
const bodyStyle = document.body.style;
|
||||
bodyStyle.width = "";
|
||||
bodyStyle.overflow = "";
|
||||
anzhiyu.animateOut(document.querySelector("#local-search .search-dialog"), "search_close .5s");
|
||||
anzhiyu.animateOut($searchMask, "to_hide 0.5s");
|
||||
};
|
||||
|
||||
const searchClickFn = () => {
|
||||
document.querySelector("#search-button > .search").addEventListener("click", openSearch);
|
||||
document.querySelector("#menu-search").addEventListener("click", openSearch);
|
||||
};
|
||||
|
||||
const searchClickFnOnce = () => {
|
||||
document.querySelector("#local-search .search-close-button").addEventListener("click", closeSearch);
|
||||
$searchMask.addEventListener("click", closeSearch);
|
||||
if (GLOBAL_CONFIG.localSearch.preload) dataObj = fetchData(GLOBAL_CONFIG.localSearch.path);
|
||||
};
|
||||
|
||||
// check url is json or not
|
||||
const isJson = url => {
|
||||
const reg = /\.json$/;
|
||||
return reg.test(url);
|
||||
};
|
||||
|
||||
const fetchData = async path => {
|
||||
let data = [];
|
||||
const response = await fetch(path);
|
||||
if (isJson(path)) {
|
||||
data = await response.json();
|
||||
} else {
|
||||
const res = await response.text();
|
||||
const t = await new window.DOMParser().parseFromString(res, "text/xml");
|
||||
const a = await t;
|
||||
|
||||
data = [...a.querySelectorAll("entry")].map(item => {
|
||||
let tagsArr = [];
|
||||
if (item.querySelector("tags") && item.querySelector("tags").getElementsByTagName("tag")) {
|
||||
Array.prototype.forEach.call(item.querySelector("tags").getElementsByTagName("tag"), function (item, index) {
|
||||
tagsArr.push(item.textContent);
|
||||
});
|
||||
}
|
||||
let content = item.querySelector("content") && item.querySelector("content").textContent;
|
||||
let imgReg = /<img.*?(?:>|\/>)/gi; //匹配图片中的img标签
|
||||
let srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i; // 匹配图片中的src
|
||||
let arr = content.match(imgReg); //筛选出所有的img
|
||||
|
||||
let srcArr = [];
|
||||
if (arr) {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
let src = arr[i].match(srcReg);
|
||||
// 获取图片地址
|
||||
if (!src[1].indexOf("http")) srcArr.push(src[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
title: item.querySelector("title").textContent,
|
||||
content: content,
|
||||
url: item.querySelector("url").textContent,
|
||||
tags: tagsArr,
|
||||
oneImage: srcArr && srcArr[0],
|
||||
};
|
||||
});
|
||||
}
|
||||
if (response.ok) {
|
||||
const $loadDataItem = document.getElementById("loading-database");
|
||||
$loadDataItem.nextElementSibling.style.display = "block";
|
||||
$loadDataItem.remove();
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
const search = () => {
|
||||
if (!GLOBAL_CONFIG.localSearch.preload) {
|
||||
dataObj = fetchData(GLOBAL_CONFIG.localSearch.path);
|
||||
}
|
||||
const $input = document.querySelector("#local-search-input input");
|
||||
const $resultContent = document.getElementById("local-search-results");
|
||||
const $loadingStatus = document.getElementById("loading-status");
|
||||
|
||||
$input.addEventListener("input", function () {
|
||||
const keywords = this.value.trim().toLowerCase().split(/[\s]+/);
|
||||
if (keywords[0] !== "")
|
||||
$loadingStatus.innerHTML = '<i class="anzhiyufont anzhiyu-icon-spinner anzhiyu-pulse-icon"></i>';
|
||||
|
||||
$resultContent.innerHTML = "";
|
||||
let str = '<div class="search-result-list">';
|
||||
if (keywords.length <= 0) return;
|
||||
let count = 0;
|
||||
// perform local searching
|
||||
dataObj.then(data => {
|
||||
data.forEach(data => {
|
||||
let isMatch = true;
|
||||
let dataTitle = data.title ? data.title.trim().toLowerCase() : "";
|
||||
let dataTags = data.tags;
|
||||
let oneImage = data.oneImage ?? "";
|
||||
const dataContent = data.content
|
||||
? data.content
|
||||
.trim()
|
||||
.replace(/<[^>]+>/g, "")
|
||||
.toLowerCase()
|
||||
: "";
|
||||
const dataUrl = data.url.startsWith("/") ? data.url : GLOBAL_CONFIG.root + data.url;
|
||||
let indexTitle = -1;
|
||||
let indexContent = -1;
|
||||
let firstOccur = -1;
|
||||
// only match articles with not empty titles and contents
|
||||
if (dataTitle !== "" || dataContent !== "") {
|
||||
keywords.forEach((keyword, i) => {
|
||||
indexTitle = dataTitle.indexOf(keyword);
|
||||
indexContent = dataContent.indexOf(keyword);
|
||||
if (indexTitle < 0 && indexContent < 0) {
|
||||
isMatch = false;
|
||||
} else {
|
||||
if (indexContent < 0) {
|
||||
indexContent = 0;
|
||||
}
|
||||
if (i === 0) {
|
||||
firstOccur = indexContent;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
isMatch = false;
|
||||
}
|
||||
|
||||
// show search results
|
||||
if (isMatch) {
|
||||
if (firstOccur >= 0) {
|
||||
// cut out 130 characters
|
||||
// let start = firstOccur - 30 < 0 ? 0 : firstOccur - 30
|
||||
// let end = firstOccur + 50 > dataContent.length ? dataContent.length : firstOccur + 50
|
||||
let start = firstOccur - 30;
|
||||
let end = firstOccur + 100;
|
||||
let pre = "";
|
||||
let post = "";
|
||||
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if (start === 0) {
|
||||
end = 100;
|
||||
} else {
|
||||
pre = "...";
|
||||
}
|
||||
|
||||
if (end > dataContent.length) {
|
||||
end = dataContent.length;
|
||||
} else {
|
||||
post = "...";
|
||||
}
|
||||
|
||||
let matchContent = dataContent.substring(start, end);
|
||||
|
||||
// highlight all keywords
|
||||
keywords.forEach(keyword => {
|
||||
const regS = new RegExp(keyword, "gi");
|
||||
matchContent = matchContent.replace(regS, '<span class="search-keyword">' + keyword + "</span>");
|
||||
dataTitle = dataTitle.replace(regS, '<span class="search-keyword">' + keyword + "</span>");
|
||||
});
|
||||
|
||||
str += '<div class="local-search__hit-item">';
|
||||
if (oneImage) {
|
||||
str += `<div class="search-left"><img src=${oneImage} alt=${dataTitle} data-fancybox='gallery'>`;
|
||||
} else {
|
||||
str += '<div class="search-left" style="width:0">';
|
||||
}
|
||||
|
||||
str += "</div>";
|
||||
|
||||
if (oneImage) {
|
||||
str +=
|
||||
'<div class="search-right"><a href="' +
|
||||
dataUrl +
|
||||
'" class="search-result-title">' +
|
||||
dataTitle +
|
||||
"</a>";
|
||||
} else {
|
||||
str +=
|
||||
'<div class="search-right" style="width: 100%"><a href="' +
|
||||
dataUrl +
|
||||
'" class="search-result-title">' +
|
||||
dataTitle +
|
||||
"</a>";
|
||||
}
|
||||
|
||||
count += 1;
|
||||
|
||||
if (dataContent !== "") {
|
||||
str +=
|
||||
'<p class="search-result" onclick="pjax.loadUrl(`' +
|
||||
dataUrl +
|
||||
'`)">' +
|
||||
pre +
|
||||
matchContent +
|
||||
post +
|
||||
"</p>";
|
||||
}
|
||||
if (dataTags.length) {
|
||||
str += '<div class="search-result-tags">';
|
||||
|
||||
for (let i = 0; i < dataTags.length; i++) {
|
||||
const element = dataTags[i].trim();
|
||||
|
||||
str +=
|
||||
'<a class="tag-list" href="/tags/' +
|
||||
element +
|
||||
'/" data-pjax-state="" one-link-mark="yes">#' +
|
||||
element +
|
||||
"</a>";
|
||||
}
|
||||
|
||||
str += "</div>";
|
||||
}
|
||||
}
|
||||
str += "</div></div>";
|
||||
}
|
||||
});
|
||||
if (count === 0) {
|
||||
str +=
|
||||
'<div id="local-search__hits-empty">' +
|
||||
GLOBAL_CONFIG.localSearch.languages.hits_empty.replace(/\$\{query}/, this.value.trim()) +
|
||||
"</div>";
|
||||
}
|
||||
str += "</div>";
|
||||
$resultContent.innerHTML = str;
|
||||
if (keywords[0] !== "") $loadingStatus.innerHTML = "";
|
||||
window.pjax && window.pjax.refresh($resultContent);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
searchClickFn();
|
||||
searchClickFnOnce();
|
||||
|
||||
// pjax
|
||||
window.addEventListener("pjax:complete", () => {
|
||||
!anzhiyu.isHidden($searchMask) && closeSearch();
|
||||
searchClickFn();
|
||||
});
|
||||
});
|
||||
130
themes/anzhiyu/source/js/tw_cn.js
Normal file
130
themes/anzhiyu/source/js/tw_cn.js
Normal file
File diff suppressed because one or more lines are too long
1435
themes/anzhiyu/source/js/utils.js
Normal file
1435
themes/anzhiyu/source/js/utils.js
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user