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 = "
";
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 = `- `
out += ``
if (item.children.length > 0) {
out += ``
}
out += "
"
return out;
}
finalMenus.forEach(item => {
result += outHtml(item, menuIndex)
})
}
result += "
"
$("#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("")
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('提交中...');
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: `${html}
`,
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("" + 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(`
${res.description}
`);
el.addClass("loaded");
}, 'json').fail((err) => {
el.html(` 请求Github项目详情异常:${repo}
`)
});
}
})
}
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()
}
)