Typecho-Theme-Puock/assets/js/puock.js

1185 lines
42 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const puockGlobalData = {
loads: {}
}
const TYPE_PRIMARY = "primary"
const TYPE_WARNING = "warning"
const TYPE_DANGER = "danger"
const TYPE_SUCCESS = "success"
const TYPE_INFO = "info"
class Puock {
data = {
tag: 'puock',
pc:true,
params: {
home: null,
use_post_menu: false,
is_single: false,
is_pjax: false,
vd_comment: false,
vd_gt_id: null,
vd_type: null,
main_lazy_img: false,
link_blank_open: false,
async_view_id: null,
mode_switch: false,
async_view_generate_time: null,
off_img_viewer:false,
off_code_highlighting:false
},
comment: {
loading: false,
time: 5,
val: null,
replyId: null
},
instance: {},
modalStorage: {}
}
// 全局一次加载或注册的事件
onceInit() {
this.pageInit()
$(document).on("click", ".fancybox", () => {
return false;
});
$(document).on("click", "#rb-float-actions>div", (e) => {
const el = $(this.ct(e));
const to = el.data("to");
if (to) {
const scroll_val = to === 'top' ? 0 : window.document.body.clientHeight;
$('html,body').stop().animate({scrollTop: scroll_val}, 50)
return;
}
const toArea = el.data("to-area");
if (toArea) {
this.gotoArea(toArea)
}
});
$(document).on("click", ".colorMode", () => {
this.modeChange(null, true);
});
if (this.data.params.is_pjax) {
this.instanceClickLoad()
}
this.initBasicDOMEvent()
this.sidebarMenuEventInit()
this.searchInit()
this.eventShareStart()
this.modeInit();
this.registerMobileMenu()
this.registerModeChangeEvent()
this.eventCommentPageChangeEvent()
this.eventCommentPreSubmit()
this.eventSmiley()
this.eventOpenCommentBox()
this.eventCloseCommentBox()
this.eventSendPostLike()
this.eventPostMainBoxResize()
this.swiperOnceEvent()
this.initModalToggle()
this.detectDevice()
window.addEventListener('resize', ()=>this.detectDevice());
layer.config({shade: 0.5})
}
pageInit() {
this.loadParams()
this.pageChangeInit()
if (this.data.params.is_single) {
if (this.data.params.use_post_menu) {
this.generatePostMenuHTML()
}
}
}
instanceClickLoad() {
InstantClick.init('mousedown');
InstantClick.go = (url) => {
const link = document.createElement('a');
link.href = url;
document.body.appendChild(link);
link.click();
}
InstantClick.on('change', (e) => {
this.loadParams();
this.pageChangeInit()
})
// InstantClick.on('receive',(url, body, title)=>{
// console.log(body)
// this.loadParams($(body))
// })
this.loadCommentInfo();
}
ct(e) {
return e.currentTarget
}
detectDevice() {
const screenWidth = window.innerWidth;
this.data.pc = screenWidth >= 768
}
initBasicDOMEvent() {
// el show or hide event
$(document).on("click", ".toggle-el-show-hide", (e) => {
const el = $(this.ct(e));
const target = $(el.attr("data-target"));
const self = $(el.attr("data-self"));
const modalTitle = el.attr("data-modal-title");
if (target.hasClass("d-none")) {
self.addClass("d-none");
target.removeClass("d-none");
} else {
self.removeClass("d-none");
target.addClass("d-none");
}
if (modalTitle) {
el.closest(".modal").find(".modal-title").text(modalTitle);
}
});
// form ajax submit
$(document).on("submit", ".ajax-form", (e) => {
e.preventDefault();
const form = $(this.ct(e));
const formEls = form.find(":input")
if (formEls.length === 0) {
this.toast('表单元素为空', TYPE_DANGER)
return false;
}
for (let i = 0; i < formEls.length; i++) {
const el = $(formEls[i]);
if (el.attr("data-required") !== undefined && el.val() === "") {
this.toast(el.attr("data-tip") || el.attr("placeholder"), TYPE_WARNING)
return false;
}
}
const validateType = form.data("validate");
const startSubmit = (args = {}) => {
const url = form.attr("action");
const method = form.attr("method");
const data = this.parseFormData(form, args);
const dataType = "json";
const successTip = form.attr("data-success");
const errorTip = form.attr("data-error");
const loading = this.startLoading()
$.ajax({
url, method, data, dataType,
success: (res) => {
this.stopLoading(loading)
if (res.code === 0 || res.success) {
this.toast(res.msg || successTip, TYPE_SUCCESS)
if (form.data("no-reset") === undefined) {
form.trigger("reset")
}
if (res.data) {
const resData = res.data
if (resData.action) {
setTimeout(() => {
switch (resData.action) {
case 'reload':
this.goUrl(window.location.href)
break
}
}, 500)
}
}
} else {
this.toast(res.msg || res.data || errorTip, TYPE_DANGER)
// this.loadCommentCaptchaImage(form, true)
}
},
error: (e) => {
this.stopLoading(loading)
this.toast(`请求错误:${e.statusText}`, TYPE_DANGER)
// this.loadCommentCaptchaImage(form, true)
}
})
}
if (validateType === 'gt') {
this.gt.validate((code) => {
startSubmit(code)
});
} else {
startSubmit()
}
return false;
})
}
pageLinkBlankOpenInit() {
if (this.data.params.link_blank_open) {
$(".entry-content").find("a").each((_, item) => {
$(item).attr('target', 'blank')
})
}
}
searchInit() {
const toggle = () => {
const search = $("#search");
const open = search.attr("data-open") === "true";
let tag = open ? 'Out' : 'In';
search.attr("class", "animated fade" + tag + "Left");
$("#search-backdrop").attr("class", "modal-backdrop animated fade" + tag + "Right");
search.attr("data-open", !open);
if (!open) {
search.find("input").focus();
}
}
$(document).on("click", ".search-modal-btn", () => {
toggle();
});
$(document).on("click", "#search-backdrop", () => {
toggle();
})
$(document).on("submit", ".global-search-form", (e) => {
e.preventDefault();
const el = $(this.ct(e));
this.goUrl(el.attr("action") + "/?" + el.serialize())
})
}
goUrl(url) {
if (this.data.params.is_pjax) {
InstantClick.go(url)
} else {
window.location.href = url
}
}
gt = {
validate: (success = undefined) => {
this.data.instance.gt_callback = success
// this.data.instance.gt.showCaptcha();
}
}
rippleInit() {
const args = {
debug: false,
on: 'mousedown',
opacity: 0.4,
color: "var(--pk-c-light)",
multi: false,
duration: 0.6,
rate: function (pxPerSecond) {
return pxPerSecond;
},
easing: 'linear'
}
jQuery.ripple(".btn", args);
jQuery.ripple(".ww", args);
}
eventShareStart() {
$(document).on("click", ".share-to", (e) => {
const id = $(this.ct(e)).attr("data-id");
if (id === 'wx') return;
const url = window.location.href;
const title = $("#post-title").text();
const wb_key = '';
let to = null;
switch (id) {
case 'wb':
to = 'https://service.weibo.com/share/share.php?pic=&title=' + title + '&url=' + url + '&appkey=' + wb_key;
break;
case 'qzone':
to = 'https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?title=' + title + '&url=' + url;
break;
case 'tw':
to = 'https://twitter.com/intent/tweet?url=' + url;
break;
case 'fb':
to = 'https://www.facebook.com/sharer.php?u' + url;
break;
}
if (to) window.open(to, '_blank');
});
}
sidebarMenuEventInit() {
let currentOpenSubMenu = null;
$(document).on("touchend", ".post-menu-toggle", (e) => {
e.preventDefault();
this.toggleMenu();
});
$(document).on("click", ".post-menu-toggle", () => {
this.toggleMenu();
});
$(document).on("click", ".post-menu-item", (e) => {
const el = $(this.ct(e))
const id = el.attr("data-id")
if (currentOpenSubMenu) {
const parentUl = el.parents("ul")
let curClass = "post-menu-sub-" + currentOpenSubMenu
while (true) {
if (typeof (curClass) === "undefined") {
break
}
const currentMenu = $("." + curClass)
const classStr = currentMenu.attr("class")
const und = typeof (classStr) == "undefined"
if (und || parentUl.attr("class") === currentMenu.attr("class")) {
break;
} else {
currentMenu.hide();
curClass = currentMenu.parents("ul").attr("class");
}
}
}
const subMenu = $(".post-menu-sub-" + id)
if (subMenu.length > 0) {
subMenu.show()
currentOpenSubMenu = id
}
});
$(document).on("click", ".pk-menu-to", (e) => {
const to = $(this.ct(e)).attr("href");
const headerHeight = $("#header").innerHeight();
$("html, body").stop().animate({
scrollTop: ($(to).offset().top - headerHeight - 10) + "px"
}, {
duration: 50,
easing: "swing"
});
if(!this.data.pc){
this.toggleMenu()
}
return false;
});
}
toggleMenu() {
const menuContainer = $("#post-menus");
const menuButton = $("#post-menu-state");
const className = "data-open";
const isOpen = menuButton.hasClass(className);
if (isOpen) {
// 关闭菜单
menuContainer.removeClass("show");
menuButton.removeClass(className);
} else {
// 打开菜单
menuContainer.addClass("show");
menuButton.addClass(className);
}
}
lazyLoadInit(parent = null, el = '.lazy') {
if (window.lozad) {
const observer = lozad([el, 'img[data-lazy="true"]'], {
rootMargin: '10px 0px',
threshold: 0.1,
enableAutoReload: true,
load: (el) => {
el.classList.add('loaded');
el.src = el.getAttribute('data-src');
}
});
observer.observe();
}
}
loadParams() {
this.data.params = puock_metas;
//this.data.commentVd = this.data.params.vd_comment === 'on';
}
initReadProgress() {
const readProgress = $("#page-read-progress .progress-bar");
document.addEventListener('scroll', () => {
const a = window.scrollY / (document.documentElement.scrollHeight - window.innerHeight) * 100;
readProgress.attr("style", "width:" + a.toFixed(0) + "%");
});
}
tooltipInit(el = $("[data-bs-toggle=\"tooltip\"]")) {
[...el].map(tooltipTriggerEl => {
new bootstrap.Tooltip(tooltipTriggerEl, {
placement: 'bottom', trigger: 'hover'
})
})
}
pageChangeInit() {
this.initReadProgress()
this.modeInit();
this.loadCommentInfo();
this.katexParse();
this.initCodeHighlight();
this.pageLinkBlankOpenInit()
this.initGithubCard();
this.keyUpHandle();
this.loadHitokoto();
// this.asyncCacheViews();
this.swiperInit();
// this.validateInit();
this.rippleInit();
if (this.data.params.use_post_menu) {
this.generatePostMenuHTML()
}
this.tooltipInit()
if(!this.data.params.off_img_viewer){
jQuery(".entry-content").viewer({
navbar: false,
url: this.data.params.main_lazy_img ? 'data-src' : 'src'
});
}
const cp = new ClipboardJS('.pk-copy', {
text: (trigger) => {
const t = $(trigger)
let input = t.attr("data-cp-input")
let el = t.attr("data-cp-el")
let val = t.attr("data-cp-val")
let func = t.attr("data-cp-func")
let text;
if(typeof func !=="undefined"){
text = window[func](t)
}else if (typeof val !== "undefined") {
text = val
} else if (typeof input !== "undefined") {
text = $(input).val()
} else if (typeof el !== "undefined") {
text = $(el).text()
} else {
text = t.text()
}
return text;
},
});
cp.on("success", (e) => {
let name = $(e.trigger).attr('data-cp-title') || "";
this.toast(`复制${name}成功`)
})
cp.on("error", (e) => {
let name = $(e.trigger).attr('data-cp-title') || "";
this.toast(`复制${name}失败`, TYPE_DANGER)
})
this.lazyLoadInit()
// $('#post-main, #sidebar').theiaStickySidebar({
// additionalMarginTop: 20
// });
}
getPostMenuStructure() {
$('.entry-content').find('h1,h2,h3,h4,h5,h6').each(function(index, el) {
if (!$(el).attr('id')) {
let safeText = $(el).text().trim().replace(/\s+/g, '-').replace(/[^\w\-]/g, '').toLowerCase();
// 防止重复id
let uniqId = safeText || `heading-${index}`;
// 如果已经有相同id添加序号
let counter = 1;
while($('#' + uniqId).length > 0) {
uniqId = `${safeText}-${counter++}`;
}
$(el).attr('id', uniqId);
}
});
let res = []
for (let item of $(".entry-content").find('h1,h2,h3,h4,h5,h6')) {
res.push({name: $(item).text().trim(), level: item.tagName.toLowerCase(), id: $(item).attr("id")})
}
return res
}
generatePostMenuHTML() {
const menus = this.getPostMenuStructure();
if (menus.length > 0) {
let result = "<ul>";
if (menus.length > 0) {
const finalMenus = []
let maxLevel = 6;
const initChildren = (item) => {
item.children = []
return item
}
const getLevel = (item) => {
item.levelInt = parseInt(item.level.replace("h", ""))
if (item.levelInt < maxLevel) {
maxLevel = item.levelInt
}
return item.levelInt
}
const firstMenu = initChildren(menus[0])
const firstLevel = getLevel(firstMenu)
let loadIndex = 0;
const eqLevelFn = (unMenu, parentMen) => {
const nextUnMenu = loadMenu(unMenu, parentMen)
if (nextUnMenu != null) {
if (getLevel(nextUnMenu) === getLevel(unMenu)) {
return eqLevelFn(nextUnMenu, parentMen)
}
}
return nextUnMenu;
}
const loadMenu = (menu, parentMenu) => {
if (loadIndex >= menus.length - 1) {
return null;
}
const nextIndex = ++loadIndex;
const nextMenu = initChildren(menus[nextIndex])
const nowLevel = getLevel(menu)
const nextLevel = getLevel(nextMenu)
let unknownMenu = null;
if (nextLevel === firstLevel) {
finalMenus.push(nextMenu)
unknownMenu = loadMenu(nextMenu, null)
} else if (nextLevel > nowLevel) {
menu.children.push(nextMenu)
unknownMenu = loadMenu(nextMenu, menu)
} else if (nextLevel === nowLevel && parentMenu != null) {
parentMenu.children.push(nextMenu)
unknownMenu = loadMenu(nextMenu, parentMenu)
} else {
return nextMenu
}
if (unknownMenu != null) {
const unknownLevel = getLevel(unknownMenu)
if (unknownLevel === nowLevel) {
parentMenu.children.push(unknownMenu)
unknownMenu = eqLevelFn(unknownMenu, parentMenu)
}
}
return unknownMenu
}
finalMenus.push(firstMenu)
while (true) {
const unknownMenu = loadMenu(firstMenu, null)
if (unknownMenu == null) {
break
}
loadMenu(unknownMenu, null)
}
let menuIndex = 0;
const outHtml = (item, parent) => {
++menuIndex;
const id = menuIndex;
const pl = (item.levelInt - maxLevel) * 10
let out = `<li data-level="${item.levelInt}" style='padding-left:${pl}px'>`
out += `<a class='pk-menu-to a-link t-w-400 t-md post-menu-item' data-parent="${parent}" data-id="${id}" href='#${item.id}'><i class='fa ${item.children.length > 0 ? 'fa-angle-right' : 'fa-file-invoice'} t-sm c-sub mr-1'></i> ${item.name}</a>`
if (item.children.length > 0) {
out += `<ul class="post-menu-sub-${id}" data-parent="${parent + 1}">`
for (let child of item.children) {
out += outHtml(child, id)
}
out += `</ul>`
}
out += "</li>"
return out;
}
finalMenus.forEach(item => {
result += outHtml(item, menuIndex)
})
}
result += "</ul>"
$("#post-menu-content-items").html(result);
$(".post-menus-box").show();
}
}
initCodeHighlight(fullChange = true, bodyEl="body") {
if(this.data.params.off_code_highlighting){
return
}
if (window.hljs !== undefined) {
window.hljs.configure({ignoreUnescapedHTML: true})
$(bodyEl).find("pre").each((index, block) => {
const el = $(block);
const codeChildClass = el.children("code") ? el.children("code").attr("class") : undefined;
if (codeChildClass) {
if (codeChildClass.indexOf("katex") !== -1 || codeChildClass.indexOf("latex") !== -1 || codeChildClass.indexOf("flowchart") !== -1
|| codeChildClass.indexOf("flow") !== -1 || codeChildClass.indexOf("seq") !== -1 || codeChildClass.indexOf("math") !== -1) {
return;
}
}
if (!el.attr("id")) {
el.attr("id", "hljs-item-" + index)
el.before("<div class='pk-code-tools' data-pre-id='hljs-item-" + index + "'><div class='dot'>" +
"<i></i><i></i><i></i></div><div class='actions'><div><i class='i fa fa-copy cp-code' data-clipboard-target='#hljs-item-" + index + "'></i></div></div></div>")
window.hljs.highlightBlock(block);
window.hljs.lineNumbersBlock(block);
}
});
if (fullChange) {
const cp = new ClipboardJS('.cp-code');
cp.on("success", (e) => {
e.clearSelection();
this.toast('已复制到剪切板')
})
}
}
}
localstorageToggle(name, val = null) {
return val != null ? localStorage.setItem(name, val) : localStorage.getItem(name);
}
loadCommentInfo() {
const authorText = this.localstorageToggle("comment_author"),
emailText = this.localstorageToggle("comment_email"),
urlText = this.localstorageToggle("comment_url");
if (authorText != null && emailText != null) {
$("#comment_author").val(authorText);
$("#comment_email").val(emailText);
$("#comment_url").val(urlText);
}
}
setCommentInfo() {
this.localstorageToggle("comment_author", $("#comment_author").val());
this.localstorageToggle("comment_email", $("#comment_email").val());
this.localstorageToggle("comment_url", $("#comment_url").val());
}
modeInit() {
this.modeChange();
}
modeChange(toLight = null, isSwitch = false) {
const body = $("body");
if (typeof (toLight) === "string") {
toLight = toLight === 'true';
}
let mode = Cookies.get('mode') || 'auto'
if (toLight === null) {
toLight = mode==='light';
if(mode==='auto'){
toLight = !window.matchMedia('(prefers-color-scheme:dark)').matches
}
}
if (isSwitch) {
if(mode==='light'){
mode = 'dark'
toLight = false;
}else if(mode==='dark'){
mode = 'auto'
toLight = !window.matchMedia('(prefers-color-scheme:dark)').matches;
}else{
mode = 'light'
toLight = true;
}
console.log(mode, toLight)
}
let dn = 'd-none';
if (toLight) {
$("#logo-light").removeClass(dn);
$("#logo-dark").addClass(dn);
} else {
$("#logo-dark").removeClass(dn);
$("#logo-light").addClass(dn);
}
$(".colorMode").each((_, e) => {
const el = $(e);
let target;
if (el.prop("localName") === 'i') {
target = el;
} else {
target = $(el).find("i");
}
if (target) {
target.removeClass("fa-sun").removeClass("fa-moon").removeClass('fa-circle-half-stroke')
.addClass(mode==='auto' ? 'fa-circle-half-stroke' : (mode==='light' ? "fa-sun" : "fa-moon"));
}
})
body.removeClass(this.data.tag + "-auto")
body.removeClass(toLight ? this.data.tag + "-dark" : this.data.tag + "-light");
body.addClass(toLight ? this.data.tag + "-light" : this.data.tag + "-dark");
// this.localstorageToggle('light', toLight)
Cookies.set('mode', mode)
}
modeChangeListener() {
if(Cookies.get('mode')==='auto'){
this.modeChange(!window.matchMedia('(prefers-color-scheme:dark)').matches);
}
}
registerModeChangeEvent() {
if (this.data.params.mode_switch) {
try {
window.matchMedia('(prefers-color-scheme:dark)').addEventListener('change', () => {
this.modeChangeListener()
});
} catch (ex) {
window.matchMedia('(prefers-color-scheme:dark)').addListener(() => {
this.modeChangeListener()
});
}
}
}
infoToastShow(text, title = '提示') {
const infoToast = $('#infoToast');
$("#infoToastTitle").html(title);
$("#infoToastText").html(text);
infoToast.modal('show');
}
registerMobileMenu() {
const fn = (s) => {
if (typeof (s) !== 'string') {
s = 'Out'
}
$("#mobile-menu").attr("class", "animated fade" + s + "Left");
$("#mobile-menu-backdrop").attr("class", "modal-backdrop animated fade" + s + "Right");
}
$(document).on("click", "#mobile-menu-backdrop", fn);
$(document).on("click", ".mobile-menu-close", fn);
$(document).on("click", ".mobile-menu-s", () => {
fn('In');
});
}
gotoArea(el, speed = 50) {
const top = $(el).offset().top - $("#header").height() - 10;
$('html,body').stop().animate({scrollTop: top}, speed);
}
pushAjaxCommentHistoryState(href) {
history.pushState({foo: "bar"}, "page 2", href);
}
eventCommentPageChangeEvent() {
$(document).on('click', '.comment-ajax-load a.page-numbers', (e) => {
const postCommentsEl = $("#post-comments");
const loadBox = $("#comment-ajax-load");
$("#comment-cancel").click();
let href = $(this.ct(e)).attr("href");
this.pushAjaxCommentHistoryState(href);
postCommentsEl.html(" ");
this.gotoArea("#comments");
loadBox.removeClass('d-none');
$.post(href, {}, (data) => {
postCommentsEl.html($(data).find("#post-comments"));
loadBox.addClass('d-none');
this.initCodeHighlight(false);
this.lazyLoadInit(postCommentsEl);
}).fail(() => {
location = href;
});
return false;
})
}
parseFormData(formEl, args = {}) {
const dataArr = formEl.serializeArray();
const data = {...args};
for (let i = 0; i < dataArr.length; i++) {
data[dataArr[i].name] = dataArr[i].value;
}
return jQuery.param(data);
}
eventCommentPreSubmit() {
$(document).on('submit', '#comment-form', (e) => {
e.preventDefault();
if ($("#comment-logged").val() === '0' && ($.trim($("#comment_author").val()) === '' || $.trim($("#comment_email").val()) === '')) {
this.toast('评论信息不能为空', TYPE_WARNING);
return;
}
if ($.trim($("#comment").val()) === '') {
this.toast('评论内容不能为空', TYPE_WARNING);
return;
}
if (this.data.params.vd_comment) {
if (this.data.params.vd_type === 'img') {
if ($.trim($("#comment-vd").val()) === '') {
this.toast('验证码不能为空', TYPE_WARNING);
return;
}
} else {
this.gt.validate((code) => {
this.commentSubmit(this.ct(e), code)
})
return;
}
}
this.commentSubmit(this.ct(e))
})
}
commentSubmit(target, args = {}) {
let submitUrl = $("#comment-form").attr("action");
this.commentFormLoadStateChange();
const el = $(target);
$.ajax({
url: submitUrl,
data: this.parseFormData(el, args),
type: el.attr('method'),
success: (data) => {
this.toast('评论已提交成功', TYPE_SUCCESS);
$("#comment-vd").val("");
$("#comment").val("");
// 获取整个评论区域的新内容
const newComments = $(data).find("#comments").html();
// 替换当前评论区域
$("#comments").html(newComments);
// 重置评论表单状态
$("#comment-form").trigger("reset");
$("#comment-cancel").click();
this.commentFormLoadStateChange();
this.setCommentInfo();
// 重新初始化相关组件
this.initCodeHighlight(false);
this.lazyLoadInit();
this.tooltipInit();
// 重新绑定事件
this.eventCommentPageChangeEvent();
this.eventOpenCommentBox();
this.eventCloseCommentBox();
// 滚动到评论区域
this.gotoArea("#comments");
},
error: (res) => {
this.commentFormLoadStateChange();
let msg = "评论提交失败";
if (res.responseJSON && res.responseJSON.msg) {
msg = res.responseJSON.msg;
}
this.toast(msg, TYPE_DANGER);
}
});
}
commentFormLoadStateChange() {
const commentSubmit = $("#comment-submit");
if (this.data.comment.loading) {
commentSubmit.html("请等待" + this.data.comment.time + "s");
this.data.comment.val = setInterval(() => {
if (this.data.comment.time <= 1) {
clearInterval(this.data.comment.val);
commentSubmit.html("提交评论");
commentSubmit.removeAttr("disabled");
this.data.comment.time = 5;
} else {
--this.data.comment.time;
commentSubmit.html("请等待" + this.data.comment.time + "s");
}
}, 1000);
} else {
commentSubmit.html('<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true"></span>提交中...');
commentSubmit.attr("disabled", true)
}
this.data.comment.loading = !this.data.comment.loading;
}
eventOpenCommentBox() {
$(document).on("click", "[id^=comment-reply-]", (e) => {
this.data.comment.replyId = $(this.ct(e)).attr("data-id");
if ($.trim(this.data.comment.replyId) === '') {
this.toast('结构有误', TYPE_DANGER);
return;
}
const cf = $("#comment-form"),
cb = $("#comment-box-" + this.data.comment.replyId);
cf.addClass("box-sw");
cb.removeClass("d-none").append(cf);
$("#comment-cancel").removeClass("d-none");
$("#comment").val("");
$("#comment_parent").val(this.data.comment.replyId);
})
}
eventCloseCommentBox() {
$(document).on("click", "#comment-cancel", () => {
const cf = $("#comment-form"),
cb = $("#comment-box-" + this.data.comment.replyId);
cf.removeClass("box-sw");
cb.addClass("d-none");
$("#comment-form-box").append(cf);
$("#comment-cancel").addClass("d-none");
this.data.comment.replyId = null;
})
}
eventSendPostLike() {
let lastSendTime = 0;
let throttleTimeMs = 3000;
$(document).on("click", "#post-like", (e) => {
const currentTime = new Date().getTime();
if (currentTime - lastSendTime < throttleTimeMs) {
this.toast("操作过于频繁", TYPE_WARNING);
return;
}
lastSendTime = currentTime;
const vm = $(this.ct(e));
let cid = vm.attr("data-id");
// 发送 AJAX 请求到当前文章页面
$.ajax({
url: window.location.href,
type: 'POST',
data: {
likeup: 1,
cid: cid
},
dataType: 'json',
success: (response) => {
// 检查返回的数据格式并更新点赞数
if (response.success) {
vm.find("span").html(response.likes);
vm.addClass("bg-primary text-light");
this.toast("点赞成功", TYPE_SUCCESS);
} else {
this.toast(response.msg || "点赞失败", TYPE_WARNING);
}
},
error: () => {
this.toast('点赞异常', TYPE_DANGER);
}
});
})
}
eventSmiley() {
$(document).on('click', '.smiley-img', (e) => {
const comment = $("#comment");
comment.val(comment.val() + ' ' + $(this.ct(e)).attr("data-id") + ' ');
layer.closeAll();
})
}
startLoading() {
return layer.load(0, {
shade: [0.5, '#000']
})
}
stopLoading(id = null) {
layer.close(id)
}
getRemoteHtmlNode(url, callback) {
const loading = this.startLoading()
$.ajax({
url: url,
type: 'GET',
success: (res)=>{
this.stopLoading(loading)
callback(res)
},
error: (err)=> {
console.error(err)
this.stopLoading(loading)
this.toast("获取内容节点数据失败", TYPE_DANGER)
}
})
}
initModalToggle() {
$(document).on("click", ".pk-modal-toggle", (e) => {
const el = $(this.ct(e));
const noTitle = el.data("no-title") !== undefined;
const noPadding = el.data("no-padding") !== undefined;
const title = el.attr("title") || el.data("title") || '提示';
const url = el.data("url");
const onceLoad = el.data("once-load")
const id = SparkMD5.hash(url)
if (onceLoad && this.data.modalStorage[id]) {
this.modalLoadRender(id, this.data.modalStorage[id], title, noTitle, noPadding)
} else {
this.getRemoteHtmlNode(url, (res) => {
if (onceLoad) {
if (!this.data.modalStorage[id]) {
this.data.modalStorage[id] = res;
}
}
this.modalLoadRender(id, res, title, noTitle, noPadding)
})
}
})
}
modalLoadRender(dataId, html, title, noTitle, noPadding) {
const id = "pk-modal-" + dataId;
layer.open({
type: 1,
title: noTitle ? false : title,
content: `<div id="${id}" style='${noPadding ? '' : 'padding: 20px'}' class='fs14'>${html}</div>`,
shadeClose: true,
})
const idEl = $("#" + id);
this.lazyLoadInit(idEl);
this.tooltipInit(idEl.find("[data-bs-toggle=\"tooltip\"]"));
}
eventPostMainBoxResize() {
$(document).on("click", ".post-main-size", () => {
const postMain = $("#post-main"),
postSlider = $("#sidebar"),
min = postMain.hasClass("col-lg-8");
postMain.removeClass(min ? "col-lg-8" : "col-lg-12");
postMain.addClass(min ? "col-lg-12" : "col-lg-8");
min ? postSlider.removeClass("d-lg-block") : postSlider.addClass("d-lg-block");
})
}
katexParse() {
return;
if (typeof katex !== 'undefined') {
const ks = $(document).find(".language-katex");
const kl = $(document).find(".language-inline");
console.log(ks, kl)
if (ks.length > 0) {
ks.parent("pre").attr("style", "text-align: center; background: none;");
ks.addClass("katex-container").removeClass("language-katex");
$(".katex-container").each((_, v) => {
this.katexItemParse($(v))
});
}
if (kl.length > 0) {
kl.each((_, v) => {
this.katexItemParse($(v))
});
}
}
}
katexItemParse(item) {
const katexText = item.text();
const el = item.get(0);
if (item.parent("code").length === 0) {
try {
katex.render(katexText, el)
} catch (err) {
item.html("<span class='err'>" + err)
}
}
}
initGithubCard() {
$.each($(".github-card"), (index, _el) => {
const el = $(_el);
const repo = el.attr("data-repo");
if (repo) {
$.get(`https://api.github.com/repos/${repo}`, (res) => {
const link_html = `class="hide-hover" href="${res.html_url}" target="_blank" rel="noreferrer"`;
el.html(`<div class="card-header"><i class="fa-brands fa-github"></i><a ${link_html}>${res.full_name}</a></div>
<div class="card-body">${res.description}</div>
<div class="card-footer">
<div class="row">
<div class="col-4"><i class="fa-regular fa-star"></i><a ${link_html}>${res.stargazers_count}</a></div>
<div class="col-4"><i class="fa-solid fa-code-fork"></i><a ${link_html}>${res.forks}</a></div>
<div class="col-4"><i class="fa-regular fa-eye"></i><a ${link_html}>${res.subscribers_count}</a></div>
</div>
</div>
`);
el.addClass("loaded");
}, 'json').fail((err) => {
el.html(`<div class="alert alert-danger"><i class="fa fa-warning"></i>&nbsp;请求Github项目详情异常${repo}</div>`)
});
}
})
}
keyUpHandle() {
const prevOrNextEl = $(".single-next-or-pre")
if (prevOrNextEl) {
window.onkeyup = function (event) {
if('BODY'===event.target?.tagName){
let url = null;
switch (event.key) {
case 'ArrowLeft': {
url = prevOrNextEl.find("a[rel='prev']").attr("href");
break
}
case 'ArrowRight': {
url = prevOrNextEl.find("a[rel='next']").attr("href");
break
}
}
if (url) {
window.location = url
}
}
}
}
}
swiperInit() {
$("[data-swiper='init']").each((_, _el) => {
const el = $(_el);
const swiperClass = el.attr("data-swiper-class");
const elArgs = el.attr("data-swiper-args");
let args = {}
if (elArgs) {
args = JSON.parse(elArgs)
}
new Swiper('.' + swiperClass, args);
});
}
swiperOnceEvent() {
$(document).on("click", ".swiper-slide a", (e) => {
if (this.data.params.is_pjax) {
e.preventDefault();
this.goUrl(e.currentTarget.href)
}
});
}
loadHitokoto() {
setTimeout(() => {
$(".widget-puock-hitokoto").each((_, v) => {
const el = $(v);
const api = el.attr("data-api") || "https://v1.hitokoto.cn/"
$.get(api, (res) => {
el.find(".t").text(res.hitokoto ?? res.content ?? "无内容");
el.find('.f').text(res.from);
el.find('.fb').removeClass("d-none");
}, 'json').fail((err) => {
console.error(err)
el.find(".t").text("加载失败:" + err.responseText || err);
el.remove(".fb");
})
})
}, 300)
}
toast(msg, type = TYPE_PRIMARY, options = {}) {
options = Object.assign({
duration: 2600,
close: false,
position: 'right',
gravity: 'bottom',
offset: {},
className: 't-' + type,
}, options)
const t = Toastify({
text: msg,
...options
});
t.showToast();
return t;
}
}
jQuery(() => {
if (window.$ === undefined) {
window.$ = jQuery;
}
window.Puock = new Puock()
window.Puock.onceInit()
}
)