var $body = (window.opera) ? (document.compatMode == "CSS1Compat" ? $('html') : $('body')) : $('html,body');
var storage = window.localStorage;
const HTML_PAGE_AJAX_HEADERS = {
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
};
const DEFAULT_LIST_LOADING_HTML = '
';
const PHOTO_LIST_LOADING_HTML = '';
var lazyLoadInstance = new LazyLoad({});
function highlightMenu() {
$('.left_menu_box ul li').removeClass('current-pjax-item')
// 路径映射表
const pathMap = {
'/moments': '/',
'/tags': '/content',
'/archives': '/archives',
'/categories': '/content'
}
// 获取清洗后的 pathname(去掉 ? 和 #)
function getPathname(url) {
const cleanUrl = url.substring(0,
url.indexOf('?') === -1
? (url.indexOf('#') === -1 ? url.length : url.indexOf('#'))
: url.indexOf('?')
)
return new URL(cleanUrl).pathname
}
// 从长到短匹配路径映射(支持 /categories/shi 匹配 /categories)
function getTargetPathname(pathname) {
const segments = pathname.split('/').filter(Boolean)
for (let i = segments.length; i >= 0; i--) {
const currentPath = '/' + segments.slice(0, i).join('/')
if (pathMap[currentPath]) return pathMap[currentPath]
}
return pathname // 无映射则返回原路径
}
const currentPathname = getPathname(location.href)
const targetPathname = getTargetPathname(currentPathname)
let hasMatched = false
// 遍历一级菜单匹配
$('.left_menu_box ul li a').each((i, e) => {
const menuPathname = getPathname(e.href)
if (targetPathname === menuPathname) {
e.parentElement.classList.add('current-pjax-item')
hasMatched = true
}
})
// 兜底匹配 /navigator
if (!hasMatched) {
$('.left_menu_box ul li a').each((i, e) => {
const menuPathname = getPathname(e.href)
if (menuPathname === '/navigator') {
e.parentElement.classList.add('current-pjax-item')
}
})
}
// 高亮完成后再滚动,确保当前项在导航容器内可见并尽量居中。
const activeMenuLink = document.querySelector('.left_menu_box ul li.current-pjax-item a');
if (activeMenuLink && typeof activeMenuLink.scrollIntoView === 'function') {
activeMenuLink.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'center'
});
}
}
function closeMomentPushModal() {
const modal = document.getElementById('create_post_box');
if (!modal || !window.UIkit || typeof UIkit.modal !== 'function') return;
try {
UIkit.modal(modal).hide();
} catch (e) { }
}
function reloadCurrentPageByPjax(loadType) {
if (window.pjax && typeof window.pjax.loadUrl === 'function') {
try {
$.removeCookie('load_type', { path: '/' });
window.pjax.loadUrl(window.location.href, {
history: false,
scrollTo: false
});
return;
} catch (e) { }
}
if (loadType) $.cookie('load_type', loadType, { path: '/' });
location.reload();
}
function buildRelativeUrl(url) {
const relativeUrl = url.pathname + url.search + url.hash;
try {
return decodeURI(relativeUrl);
} catch (e) {
return relativeUrl;
}
}
function removePageParamFromUrl(url) {
try {
const targetUrl = new URL(url || window.location.href, window.location.origin);
targetUrl.searchParams.delete('page');
return buildRelativeUrl(targetUrl);
} catch (e) {
return url || window.location.pathname;
}
}
function syncPageParamToUrl(page) {
const pageNumber = parseInt(page, 10);
if (!pageNumber || pageNumber < 1) return;
const url = new URL(window.location.href);
url.pathname = url.pathname.replace(/\/page\/\d+\/?$/, '') || '/';
if (url.pathname !== '/' && url.pathname.endsWith('/')) {
url.pathname = url.pathname.slice(0, -1);
}
if (pageNumber > 1) {
url.searchParams.set('page', pageNumber);
} else {
url.searchParams.delete('page');
}
const displayUrl = buildRelativeUrl(url);
const currentState = history.state && typeof history.state === 'object' ? history.state : {};
// PJAX uses history.state.url when restoring a popstate entry. Keep it in
// sync with the visible URL after AJAX pagination changes the current page.
history.replaceState(
Object.assign({}, currentState, { url: displayUrl, page: pageNumber }),
'',
displayUrl
);
}
function getPageNumberFromUrl(urlValue) {
try {
const targetUrl = new URL(urlValue || window.location.href, window.location.origin);
const pageParam = parseInt(targetUrl.searchParams.get('page'), 10);
if (pageParam && pageParam > 0) return pageParam;
const pathPage = targetUrl.pathname.match(/\/page\/(\d+)\/?$/);
return pathPage ? parseInt(pathPage[1], 10) : 1;
} catch (e) {
const pageMatch = String(urlValue || '').match(/[?&]page=(\d+)|\/page\/(\d+)\/?$/);
return pageMatch ? parseInt(pageMatch[1] || pageMatch[2], 10) : 1;
}
}
function buildPageUrlFromCurrent(page) {
const pageNumber = parseInt(page, 10);
if (!pageNumber || pageNumber < 1) return buildRelativeUrl(new URL(window.location.href));
const url = new URL(window.location.href);
const pathPageReg = /\/page\/\d+\/?$/;
const usesPathPage = !url.searchParams.has('page') && pathPageReg.test(url.pathname);
if (usesPathPage) {
if (pageNumber > 1) {
url.pathname = url.pathname.replace(pathPageReg, '/page/' + pageNumber);
} else {
url.pathname = url.pathname.replace(pathPageReg, '') || '/';
}
} else {
url.pathname = url.pathname.replace(pathPageReg, '') || '/';
if (pageNumber > 1) {
url.searchParams.set('page', pageNumber);
} else {
url.searchParams.delete('page');
}
}
if (url.pathname !== '/' && url.pathname.endsWith('/')) {
url.pathname = url.pathname.slice(0, -1);
}
return buildRelativeUrl(url);
}
function getPreviousPageContext() {
const $photosList = $('#photos_item');
if ($photosList.length) {
return {
type: 'photos',
$list: $photosList,
extract: function (data) {
return $(data).find('#photos_item .gallery-photo, .norpost_list .gallery-photo');
},
insert: function ($items, data) {
const $gallery = $('#photos_item .gallery-photos').first();
if ($gallery.length) {
$gallery.prepend($items.hide().fadeIn(300));
return $items.last();
}
const previousPhotosHtml = $(data).find('#photos_item').html();
if (previousPhotosHtml) {
this.$list.html(previousPhotosHtml);
return this.$list.find('.gallery-photo').last();
}
return $();
},
afterLoad: function () {
if (typeof pix !== 'undefined' && pix.initGalleryPhotos) pix.initGalleryPhotos();
if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update();
if ($('.gallery-photos').length > 0 && typeof waterfall === 'function') {
waterfall('.gallery-photos');
}
}
};
}
const $momentList = $('#post_item.moment_list');
if ($momentList.length) {
return {
type: 'moment',
$list: $momentList,
extract: function (data) {
return $(data).find('.moment_list .p_item');
},
insert: function ($items) {
const $previousButton = this.$list.children('#prev_pagination').first();
if ($previousButton.length) {
$previousButton.after($items.hide().fadeIn(300));
} else {
this.$list.prepend($items.hide().fadeIn(300));
}
return $items.last();
},
afterLoad: function () {
refreshAjaxPostList();
getMomentAudio();
initAgree();
if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update();
initializeMomentFold();
initDoubanDetailLinks();
}
};
}
const $postList = $('#post_item.norpost_list');
if ($postList.length) {
return {
type: 'post',
$list: $postList,
extract: function (data) {
return $(data).find('.norpost_list').children();
},
insert: function ($items) {
const $previousButton = this.$list.children('#prev_pagination').first();
if ($previousButton.length) {
$previousButton.after($items.hide().fadeIn(400));
} else {
this.$list.prepend($items.hide().fadeIn(400));
}
return $items.last();
},
afterLoad: function () {
refreshAjaxPostList();
initAgree();
if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update();
}
};
}
return null;
}
function initPreviousPageButton(page) {
const context = getPreviousPageContext();
const $oldButton = $('#prev_pagination');
if (!context) {
$oldButton.remove();
return;
}
// 有BUG:PJAX加载失败后可能会新增本不该存在的上一页按钮,不管了
if ((page === undefined || page === null) && $oldButton.length) {
return;
}
const previousPage = page !== undefined && page !== null
? parseInt(page, 10)
: getPageNumberFromUrl(window.location.href) - 1;
if (!previousPage || previousPage < 1) {
$oldButton.remove();
return;
}
const previousUrl = buildPageUrlFromCurrent(previousPage);
const buttonText = (window.Theme && Theme.prev_page) ? Theme.prev_page : '翻阅更多';
if ($oldButton.length) {
$oldButton.addClass('uk-width-1-1');
$oldButton.find('a').attr('data', previousUrl).attr('data-page', previousPage).text(buttonText).show();
context.$list.prepend($oldButton);
animatePreviousPageButton($oldButton);
return;
}
const $button = $('', {
id: 'prev_pagination',
class: 'prev-pagination uk-width-1-1'
});
const $paging = $('', { class: 'post-paging' });
const $link = $('', {
class: 'prev-page-btn',
text: buttonText
}).attr('data', previousUrl).attr('data-page', previousPage);
$button.append($paging.append($link));
context.$list.prepend($button);
animatePreviousPageButton($button);
}
function createAjaxPageSnapshot(options) {
options = options || {};
const $content = options.$content || (options.contentSelector ? $(options.contentSelector) : $());
const $pagination = options.$pagination || (options.paginationSelector ? $(options.paginationSelector) : $());
const $pagingArea = options.$pagingArea || (options.pagingAreaSelector ? $(options.pagingAreaSelector) : $());
return {
$content: $content,
contentHtml: $content.length ? $content.html() : '',
paginationSelector: options.paginationSelector,
paginationHtml: $pagination.length ? $pagination.prop('outerHTML') : '',
paginationInsert: options.paginationInsert || 'after',
$paginationAnchor: options.$paginationAnchor || $content,
$pagingArea: $pagingArea,
pagingHtml: $pagingArea.length ? $pagingArea.html() : ''
};
}
function restoreAjaxPageSnapshot(snapshot, options) {
if (!snapshot) return;
options = options || {};
const restoreContent = options.content !== false;
const restorePagination = options.pagination !== false;
const restorePaging = options.paging === true;
if (restoreContent && snapshot.$content && snapshot.$content.length) {
snapshot.$content.html(snapshot.contentHtml);
}
if (restorePagination && snapshot.paginationSelector) {
const $currentPagination = $(snapshot.paginationSelector);
if (snapshot.paginationHtml) {
if ($currentPagination.length) {
$currentPagination.replaceWith(snapshot.paginationHtml);
} else if (snapshot.$paginationAnchor && snapshot.$paginationAnchor.length) {
if (snapshot.paginationInsert === 'before') {
snapshot.$paginationAnchor.before(snapshot.paginationHtml);
} else if (snapshot.paginationInsert === 'prepend') {
snapshot.$paginationAnchor.prepend(snapshot.paginationHtml);
} else {
snapshot.$paginationAnchor.after(snapshot.paginationHtml);
}
}
} else if ($currentPagination.length) {
$currentPagination.remove();
}
}
if (restorePaging && snapshot.$pagingArea && snapshot.$pagingArea.length) {
snapshot.$pagingArea.html(snapshot.pagingHtml);
}
}
function animatePreviousPageButton($button) {
if (!$button || !$button.length) return;
if ($button.hasClass('is-visible')) return;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
$button.addClass('is-visible');
});
});
}
function getLoadMoreText() {
return (window.Theme && Theme.site_page) ? Theme.site_page : '翻阅更多';
}
function ensureLoadMoreButton(paginationSelector, insertAfterSelector) {
let $pagination = $(paginationSelector);
if (!$pagination.length) {
const paginationId = paginationSelector.charAt(0) === '#' ? paginationSelector.slice(1) : '';
$pagination = $('', paginationId ? { id: paginationId } : {});
$(insertAfterSelector).last().after($pagination);
}
let $postPaging = $pagination.find('.post-paging').first();
if (!$postPaging.length) {
$postPaging = $('', { class: 'post-paging' });
$pagination.empty().append($postPaging);
}
let $button = $postPaging.find('a').first();
if (!$button.length) {
$button = $('');
$postPaging.empty().append($button);
}
return $button;
}
function updateLoadMorePagination(paginationSelector, insertAfterSelector, data, fallbackPaginationSelector) {
const $data = $(data);
const $newPagination = $data.find(paginationSelector).first();
let newHref = $newPagination.find('a').attr('data');
if (newHref === undefined && fallbackPaginationSelector) {
newHref = $data.find(fallbackPaginationSelector + ' a').attr('data');
}
const newPaginationHtml = $newPagination.length ? $newPagination.prop('outerHTML') : '';
let $pagination = $(paginationSelector);
if (newPaginationHtml) {
if ($pagination.length) {
$pagination.replaceWith(newPaginationHtml);
} else {
$(insertAfterSelector).last().after(newPaginationHtml);
}
$pagination = $(paginationSelector);
}
if (newHref !== undefined) {
const $paginationBtn = ensureLoadMoreButton(paginationSelector, insertAfterSelector);
$paginationBtn.attr('data', newHref).text(getLoadMoreText()).show();
$(paginationSelector).show();
$(paginationSelector + ' .post-paging').show();
} else if (newPaginationHtml) {
// 最后一页仍保留页码跳转控件,只隐藏不存在的下一页按钮。
$(paginationSelector + ' .post-paging > a').hide();
$(paginationSelector).show();
$(paginationSelector + ' .post-paging').show();
} else {
$(paginationSelector + ' a').hide();
$(paginationSelector).hide();
}
initPageJumpSteppers();
return newHref;
}
function showListLoading(selector, loadingHtml) {
$(selector).html(loadingHtml || DEFAULT_LIST_LOADING_HTML);
}
function hidePagination(selector) {
$(selector).hide();
}
function setCategoryLinkActive($link, childSelector) {
$link.addClass('active').parent().siblings().children(childSelector || 'a').removeClass('active');
if (window.pix && typeof pix.centerCategoryNavActive === 'function') {
pix.centerCategoryNavActive($link);
}
}
function cacheCommentFormForAjax() {
var temp = $("#comment_form_reset");
var formHtml = $("#t_commentform").prop('outerHTML');
temp.html(formHtml);
}
function refreshAjaxPostList() {
const postListElement = document.getElementById("post_item");
window.pjax && window.pjax.refresh(postListElement);
}
function restoreAjaxSnapshotWithError(pageSnapshot, restoreOptions, message) {
restoreAjaxPageSnapshot(pageSnapshot, restoreOptions);
cocoMessage.error(message || '内容获取失败');
}
function restorePagingSnapshotWithError(pageSnapshot, message) {
restoreAjaxSnapshotWithError(pageSnapshot, { content: false, pagination: false, paging: true }, message);
}
function buildMediaLibraryUrl(page) {
return `/apis/${Theme.moments.attachments_api}/v1alpha1/attachments?group=&page=${page}&size=10&ungrouped=false&accepts=image/*&accepts=video/*`;
}
function buildMediaLibraryItem(value) {
var src = value.status.permalink;
var mediaType = value.spec.mediaType || '';
if (mediaType.startsWith('video/')) {
return `
`;
}
return `
`;
}
function renderMediaLibraryList(data) {
$(".wp_get_media_list").empty();
$.each(data.items || [], function (i, value) {
$(".wp_get_media_list").append(buildMediaLibraryItem(value));
});
}
function updateMediaLibraryPagination(page, totalPages) {
$(".attch_nav .nex").toggle(totalPages > page);
$(".attch_nav .pre").toggle(page > 1);
}
function loadMediaLibraryPage(page) {
$.ajax({
type: "get",
url: buildMediaLibraryUrl(page),
contentType: "application/json",
success: function (data) {
renderMediaLibraryList(data);
updateMediaLibraryPagination(page, data.totalPages);
}
});
}
//话题表情添加
$(document).on('click', 'a.smile_btn', function () {
var a = $(this).html();
var textarea = $("textarea#topic_content");
var content = textarea.val();
textarea.val(content + a);
textarea.focus();
});
$(document).on('click', '.smile_box i', function () {
var t = $(".smile_show");
t.slideToggle(100);
});
//选择话题
$(document).on('click', '.t_cat_box li', function () {
var name = $(this).find('.c_name span').html();
$('.t_cat_toogle span').html(name);
UIkit.dropdown('.t_cat_box').hide(false);
});
$(document).on('click', '.up_cat_btn', function () {
var name = $('input#add_cat').val();
if (!name) {
cocoMessage.error("请填写话题");
return false;
}
$('.t_cat_toogle span').text(name)
UIkit.dropdown('.t_cat_box').hide(false);
});
$(document).on('click', '.simi a', function () {
var visible = $(this).attr('visible');
if (visible == 'PUBLIC') {
$(this).html('').attr('visible', 'PRIVATE');
$(this).children().css({ "background": "#ddd", "color": "#c6c6c6" });
} else {
$(this).html('').attr('visible', 'PUBLIC');
$(this).children().css({ "background": "#e3efe7", "color": "#66c187" });
}
});
//消息通知
cocoMessage.config({
duration: 2000,
});
//ajax上传媒体文件到媒体库(已兼容图片/视频)
$(document).on('change', '#topic_img_up', function (e) {
e.preventDefault();
if ($('#topic_img_up').val() == '') return;
const policyName = Theme.moments.policy_name;
const groupName = Theme.moments.group_name;
var files = $('#topic_img_up')[0].files;
var imgtot = 0;
var num = $('.add_img_box .t_media_item').length;
// 修改提示语为“文件”
if (num + files.length > 9) {
cocoMessage.error("最多上传9个媒体文件");
return;
}
$.each(files, function (i, file) {
imgtot += file['size'];
});
var tot = imgtot / 1024000;
$(".up_img_btn i").hide();
$(".up_img_btn").prepend("");
$.each(files, function (i, file) {
var data = new FormData();
data.append('file', file);
policyName && data.append('policyName', policyName);
groupName && data.append('groupName', groupName);
$.ajax({
type: "POST",
url: `${Theme.moments.attachments_upload_api}`,
dataType: 'json',
data: data,
processData: false,
contentType: false,
beforeSend: function () {
$('input#topic_img_up').attr('disabled', 'disabled');
},
success: function (data) {
// 1. 获取上传后的地址
var src = data.metadata.annotations["storage.halo.run/uri"]
|| data.metadata.annotations["storage.halo.run/external-link"]
|| data.metadata.annotations["lskypro.plugin.halo.chenhe.me/image-link"];
// 2. 获取文件类型 (MIME Type)
// Halo 的 API 通常在 data.spec.mediaType 中返回类型,或者根据后缀判断
var mediaType = data.spec.mediaType || "";
var isVideo = mediaType.startsWith('video/') || /\.(mp4|webm|mov)$/i.test(src);
// 3. 动态生成预览 HTML
var mediaInner = isVideo
? ``
: `
`;
var media = ``;
$(".img_show").prepend(media);
num = $('.add_img_box .t_media_item').length;
$(".img_load_text").remove();
if (num < 10) $(".up_img_btn i").show();
$('input#topic_img_up').removeAttr('disabled');
},
error: function () {
cocoMessage.error("上传失败");
$(".img_load_text").remove();
$(".up_img_btn i").show();
$('input#topic_img_up').removeAttr('disabled');
}
});
});
});
//同步修改检查数量的提示语
function check_image_num() {
var num = $('.add_img_box .t_media_item').length;
if (num > 8) {
cocoMessage.error("最多上传9个媒体文件");
return true;
}
}
//sortable事件 隐藏input
UIkit.util.on('.img_show', 'start', function (item) {
$(".up_img_btn").hide();
});
UIkit.util.on('.img_show', 'moved', function (item) {
var img_num = $('.add_img_box .t_media_item').length;
if (img_num < 9) {
$(".up_img_btn").show();
}
});
UIkit.util.on('.img_show', 'stop', function (item) {
var img_num = $('.add_img_box .t_media_item').length;
if (img_num < 9) {
$(".up_img_btn").show();
}
});
//获取媒体库图片/视频(功能不变)
$(document).on('click', '.up_from_media a', function () {
$(".attch_nav .pre").hide();
$(".attch_nav .nex").hide();
$(".attch_nav").attr('paged', '1');
$(".wp_get_media_list").empty();
$(".show_media_box").show();
loadMediaLibraryPage(1);
});
//媒体库分页(功能不变)
$(document).on('click', '.attch_nav a', function () {
$(".wp_get_media_list").empty();
var type = $(this).attr('class');
var paged = $(".attch_nav").attr('paged');
if (type == 'nex') {
paged = parseInt(paged) + 1;
} else if (type == 'pre' && paged) {
paged = parseInt(paged) - 1;
}
$(".attch_nav").attr('paged', paged);
loadMediaLibraryPage(paged);
});
//收起媒体库(无修改)
$(document).on('click', '.show_media_box .souqi', function () {
$(".show_media_box").hide();
$(".wp_get_media_list").empty();
});
//从媒体库插入图片/视频(删除按钮样式简化)
$(document).on('click', '.wp_get_media_list li', function () {
var num = $('.add_img_box .t_media_item').length;
if (num == 8) {
$("a.up_img_btn").hide();
}
if (check_image_num()) {
return false;
}
var src = $(this).attr('data-src');
var type = $(this).attr('data-type');
var mediaHtml = '';
if (type.startsWith('video/')) {
mediaHtml = ``;
} else {
var thum = $(this).children().attr('src') || $(this).children().attr('poster');
mediaHtml = ``;
}
$(".img_show").prepend(mediaHtml);
});
//删除图片/视频(保留事件冒泡修复)
$(document).on('click', '.topic-img-de', function (e) {
e.stopPropagation();
$(this).parent().remove();
var num = $('.add_img_box .t_media_item').length;
if (num < 9) {
$("a.up_img_btn").show();
}
});
//插入外部图片链接
$(document).on('click', '.up_from_cdn a', function () {
//$(".show_media_box .souqi").click();
$(".show_cdn_media").show();
});
//取消
$(document).on('click', 'a.img_link_cancel', function () {
$(".show_cdn_media").hide();
});
//插入图片或视频链接
$(document).on('click', 'a.img_link_btn', function () {
var img_url = $("#img_link_up").val().trim();
// 1. 扩展正则判断,支持视频后缀
if (!/\.(mp4|webm|jpg|png|gif|webp|jpeg)$/i.test(img_url) || img_url == '') {
cocoMessage.error("媒体格式不正确或链接为空!");
return false;
}
if (check_image_num()) {
return false;
}
var num = $('.add_img_box .t_media_item').length;
if (num == 8) {
$("a.up_img_btn").hide();
}
var src = img_url;
// 获取后缀名并转为小写
var ext = img_url.substring(img_url.lastIndexOf('.') + 1).toLowerCase();
// 2. 判定是否为视频
var isVideo = (ext === 'mp4' || ext === 'webm');
var type = isVideo ? 'video/' + ext : 'image/' + ext;
// 3. 根据类型生成预览 HTML
var mediaPreview = '';
if (isVideo) {
mediaPreview = ``;
} else {
mediaPreview = `
`;
}
var media = ``;
$(".img_show").prepend(media);
$("#img_link_up").val('');
});
//ajax获取我的地理位置
$(document).on('click', '.loca .laqu', function () {
var gaode_key = Theme.moments.gaode_key;
var ip = '';
$.ajax({
type: "get",
url: `/apis/uc.api.security.halo.run/v1alpha1/devices`,
contentType: "application/json",
success: function (data) {
if (data.length > 0) {
var ipAddress = data[0].device.spec.ipAddress;
if (!/^10\.|^192\.|^168\.|^172\./.test(ipAddress)) {
ip = data[0].device.spec.ipAddress
}
}
$.ajax({
type: "get",
url: `https://restapi.amap.com/v3/ip?ip=${ip}&key=${gaode_key}`,
contentType: "application/json",
beforeSend: function () {
$(".loca_text").text("数据拉取中..");
},
success: function (data) {
if (data.status == '1') {
var city = 'X市';
if (typeof data.city === 'string') {
city = data.city;
}
var province = 'X省';
if (typeof data.province === 'string') {
province = data.province;
}
var loca = "" + province + " · " + city + "";
$(".loca_text").html(loca).attr("state", '1'); //设置为开启
} else {
cocoMessage.error(data.info);
}
}
});
}
});
});
//插入自定义位置【点击关闭】
$(document).on('click', 'a.set_local_btn', function (e) {
var loca = $("#set_local").val();
var state = $(".loca_text").attr('state');
if (loca == '') {
cocoMessage.error("为空则不显示位置");
$(".loca_text").text('').attr("state", '0');
$("a.close_local").text('位置已关闭').css('color', '#ddd');
$.removeCookie('mylocal', { path: '/' });
} else {
$(".loca_text").text(loca).attr("state", '1');
$("a.close_local").text('位置已开启').css('color', '#8890cc');
$.cookie('mylocal', loca, { expires: 30, path: '/' });
}
e.preventDefault();
e.stopPropagation();
UIkit.dropdown($('.local_box')).hide(0);
});
//插入自定义位置【input监控】
$(document).on('input', '#set_local', function () {
var loca = $(this).val();
var state = $(".loca_text").attr('state');
if (loca == '') {
cocoMessage.error("为空则不显示位置");
$(".loca_text").text('').attr("state", '0');
$("a.close_local").text('位置已关闭').css('color', '#ddd');
} else {
$(".loca_text").text(loca).attr("state", '1');
$("a.close_local").text('位置已开启,点击关闭').css('color', '#8890cc');
}
});
//关闭地理位置
$(document).on('click', 'a.close_local', function () {
$(".loca_text").text('').attr("state", '0');
$('#set_local, [name="set_local"]').val('');
$("a.close_local").text('位置已关闭').css('color', '#ddd');
});
$(document).on('click', '.loca_text', function () {
$("a.close_local").text('位置已开启,点击关闭').css('color', '#8890cc');
});
//发布更新瞬间
let isSubmittingMoment = false;
$(document).on('click', '.push_item', function () {
if (isSubmittingMoment) return false;
let closeLoading = null;
var content = $("#topic_content").val();
var catname = $(".t_cat_toogle span").text();
var loca = $(".loca_text").text();
var act = $('.push_item').attr('action');
var pid = $('.push_item').attr('pid');
var moment_type = $('.push_item').attr('type');
var visible = $(".simi a").attr('visible');
var min = Theme.moments.min_push_num;
if (min > 0) {
if (!content) {
cocoMessage.error("请输入内容");
return false;
}
if (content.length < min) {
cocoMessage.error("内容不得少于" + min + "个字");
return false;
}
}
let tags = [];
if (catname) {
tags.push(catname);
content += `${catname}
`;
}
get_moment_data(moment_type);
isSubmittingMoment = true;
const $btn = $(this);
$btn.attr('disabled', true).addClass('disabled');
function release() {
isSubmittingMoment = false;
$('.push_close, .push_item').prop('disabled', false);
$btn.removeClass('disabled');
}
if (act === 'push') {
let pushData = {
apiVersion: 'moment.halo.run/v1alpha1',
kind: 'Moment',
metadata: { generateName: "moment-" },
spec: {
content: {
html: content,
medium: moment_data,
raw: content
},
owner: "",
tags: tags,
visible: visible
}
};
if (loca && loca !== '数据拉取中..') {
pushData.metadata.annotations = { mylocal: loca };
}
closeLoading = cocoMessage.loading('正在发布...');
$('.push_close, .push_item').prop('disabled', true);
$.ajax({
type: "POST",
url: `/apis/${Theme.moments.push_api}/v1alpha1/moments`,
contentType: "application/json",
data: JSON.stringify(pushData),
success() {
closeLoading?.()
cocoMessage.success('发布成功!');
release();
closeMomentPushModal();
reloadCurrentPageByPjax('create');
},
error() {
$('.push_close, .push_item').prop('disabled', false);
closeLoading?.()
cocoMessage.error('发布失败!');
release();
}
});
return;
}
if (act === 'update') {
let updateData = {
apiVersion: 'moment.halo.run/v1alpha1',
kind: 'Moment',
metadata: {
name: pid,
generateName: "moment-",
finalizers: ["tag-moment-protection", "moment-protection"],
version: parseInt($('.push_item').attr('version'))
},
spec: {
content: {
html: content,
medium: moment_data,
raw: content
},
owner: $('.push_item').attr('owner'),
releaseTime: $('.push_item').attr('releaseTime'),
tags: tags,
visible: visible
}
};
if (loca && loca !== '数据拉取中..') {
updateData.metadata.annotations = { mylocal: loca };
}
closeLoading = cocoMessage.loading('正在更新...');
$('.push_close, .push_item').prop('disabled', true);
$.ajax({
type: "PUT",
url: `/apis/${Theme.moments.api}/v1alpha1/moments/${pid}`,
contentType: "application/json",
data: JSON.stringify(updateData),
success() {
closeLoading?.()
cocoMessage.success('更新成功!');
release();
closeMomentPushModal();
reloadCurrentPageByPjax('update');
},
error() {
closeLoading?.()
cocoMessage.error('更新失败!');
$('.push_close, .push_item').prop('disabled', false);
release();
}
});
}
});
//获取片刻类型参数
function get_moment_data(type) {
moment_data = [];
switch (type) {
case "image":
$(".t_media_item").each(function () {
var src = $(this).attr('data-src');
var type = $(this).attr('data-type');
var obj = {
url: src,
type: "PHOTO",
originType: type
}
moment_data.push(obj); //图片
});
break;
case "card":
$(".card_sortble .moment_card_item").each(function () {
var pid = $(this).attr('pid');
var type = $(this).attr('type');
var obj = {
url: pid,
type: "POST",
originType: type
}
moment_data.push(obj); //卡片
});
break;
case "audio":
get_audio_data();
break;
case "video":
get_video_data();
break;
}
}
//片刻音乐参数
function get_audio_data() {
var type = $('.audio_choose li.uk-active a').attr('au_type');
if (type == 'local') {
var url = $('input#moment_audio_url').val();
var obj = {
url: url,
type: "AUDIO",
originType: 'audio/' + type
}
} else {
var n_id = $('input#moment_audio_api').val();
var obj = {
url: n_id,
type: "AUDIO",
originType: 'audio/' + type
}
}
moment_data.push(obj);
}
//片刻视频参数
function get_video_data() {
var type = $('.video_choose li.uk-active a').attr('vi_type');
if (type == 'local') {
var url = $('input#moment_video_url').val();
var obj = {
url: url,
type: "VIDEO",
originType: 'video/mp4'
}
} else if (type == 'bili') {
var bvid = $('input#moment_video_bili').val();
var obj = {
url: bvid,
type: "VIDEO",
originType: 'video/bili'
}
}
moment_data.push(obj);
}
//片刻空值提示
function get_moment_error(type) {
switch (type) {
case "card":
var v = $('.show_card .moment_card_item');
if (v.length == 0) {
return false;
}
break;
case "audio":
var au_type = $('.audio_choose li.uk-active a').attr('au_type');
var url = $('input#moment_audio_url').val(); //歌曲链接
var title = $('input#moment_audio_name').val(); //标题
var cover = $('.loacl_audio .audio_left img').length; //封面
if (au_type == 'local') {
if (url == '' || title == '' || cover == 0) {
return false;
}
} else {
var n_id = $('input#moment_audio_api').val();
if (n_id == '') {
return false;
}
}
break;
case "video":
var vi_type = $('.video_choose li.uk-active a').attr('vi_type');
var url = $('input#moment_video_url').val();
if (vi_type == 'local') {
if (url == '') {
return false;
}
} else {
var bvid = $('input#moment_video_bili').val();
if (bvid == '') {
return false;
}
}
break;
}
}
// ajax分类筛选 moment
$(document).on('click', '.moment_cat_nav ul li a', function () {
var $this = $(this);
if ($this.hasClass('disabled')) {
return false;
}
$('.moment_cat_nav ul li a').addClass('disabled');
cacheCommentFormForAjax();
// --- 1. 保存旧内容---
var $momentList = $(".moment_list");
var pageSnapshot = createAjaxPageSnapshot({
$content: $momentList,
paginationSelector: '#t_pagination'
});
$(".moment_list").empty();
$('#t_pagination a').hide();
var cat = $this.attr('data');
$.ajax({
type: "GET",
url: cat,
headers: HTML_PAGE_AJAX_HEADERS,
beforeSend: function () {
showListLoading('.moment_list');
hidePagination('#t_pagination');
},
success: function (data) {
setCategoryLinkActive($this);
$('.moment_list .loading_box').remove();
var result = $(data).find(".moment_list .p_item");
$(".moment_list").append(result.fadeIn(300));
updateLoadMorePagination('#t_pagination', '.moment_list', data);
getMomentAudio();
initAgree();
if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update();
$('.moment_cat_nav ul li a').removeClass('disabled');
initializeMomentFold();
// if (typeof modify_moment_video_size === 'function') modify_moment_video_size();
if (cat.indexOf('tag=') !== -1) {
const displayUrl = removePageParamFromUrl(cat);
history.replaceState({ url: displayUrl }, '', displayUrl);
} else {
history.replaceState({ url: cat }, '', '/');
}
},
error: function () {
$('.moment_cat_nav ul li a').removeClass('disabled');
restoreAjaxSnapshotWithError(pageSnapshot);
}
});
});
// ajax分类筛选朋友圈
$(document).on('click', '.friends_cat_nav .cat-link', function () {
var $this = $(this);
if ($this.hasClass('disabled')) {
return false;
}
$('.friends_cat_nav .cat-link').addClass('disabled');
// 保留原有的表单重置逻辑(如果不需要可删除)
cacheCommentFormForAjax();
// --- 1. 保存旧内容---
var $momentList = $(".moment_list");
var pageSnapshot = createAjaxPageSnapshot({
$content: $momentList,
paginationSelector: '#t_pagination'
});
// 清空列表并隐藏分页
$(".moment_list").empty();
$('#t_pagination a').hide();
// 获取目标 URL(注意这里用的是 data-href)
var url = $this.attr('data-href');
if (!url) {
$('.friends_cat_nav .cat-link').removeClass('disabled');
return;
}
$.ajax({
type: "GET",
url: url,
headers: HTML_PAGE_AJAX_HEADERS,
beforeSend: function () {
showListLoading('.moment_list');
hidePagination('#t_pagination');
},
success: function (data) {
setCategoryLinkActive($this);
// 移除加载动画
$('.moment_list .loading_box').remove();
// 提取并插入新的列表项
var result = $(data).find(".moment_list .p_item");
$(".moment_list").append(result.fadeIn(300));
// 处理分页逻辑
updateLoadMorePagination('#t_pagination', '.moment_list', data);
// --- 功能初始化区域(根据您的实际情况启用/禁用) ---
if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update();
$('.friends_cat_nav .cat-link').removeClass('disabled');
initializeMomentFold();
initDoubanDetailLinks();
// 更新浏览器历史状态
if (typeof url === 'string') {
const displayUrl = removePageParamFromUrl(url.replace('author', 'tag'));
history.replaceState({ url: displayUrl }, '', displayUrl);
}
},
error: function () {
$('.friends_cat_nav .cat-link').removeClass('disabled');
restoreAjaxSnapshotWithError(pageSnapshot);
}
});
});
//ajax加载上一页
$(document).on('click', '#prev_pagination a', function () {
const $btn = $(this);
if ($btn.hasClass('disabled')) return false;
const href = $btn.attr('data');
const context = getPreviousPageContext();
if (!href || !context) return false;
const previousPage = parseInt($btn.attr('data-page'), 10) || Math.max(getPageNumberFromUrl(window.location.href) - 1, 1);
const $pagingArea = $('#prev_pagination .post-paging');
const pageSnapshot = createAjaxPageSnapshot({
$content: context.$list,
paginationSelector: '#prev_pagination',
paginationInsert: 'prepend',
$paginationAnchor: context.$list,
$pagingArea: $pagingArea
});
const scrollTopBeforeLoad = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
const listHeightBeforeLoad = context.$list[0] ? context.$list[0].scrollHeight : 0;
$.ajax({
type: "GET",
url: href,
headers: HTML_PAGE_AJAX_HEADERS,
beforeSend: function () {
$btn.addClass('disabled').attr('aria-disabled', 'true');
$pagingArea.html('');
},
success: function (data) {
const $items = context.extract(data);
if (!$items.length) {
restoreAjaxSnapshotWithError(pageSnapshot);
return;
}
restoreAjaxPageSnapshot(pageSnapshot, { content: false, pagination: false, paging: true });
context.insert($items, data);
context.afterLoad();
initPreviousPageButton(previousPage - 1);
syncPageParamToUrl(previousPage);
const listHeightAfterLoad = context.$list[0] ? context.$list[0].scrollHeight : listHeightBeforeLoad;
const heightDelta = Math.max(0, listHeightAfterLoad - listHeightBeforeLoad);
window.scrollTo(0, scrollTopBeforeLoad + heightDelta - 50);
$body.animate({ scrollTop: '-=100' }, 500);
},
error: function () {
restoreAjaxSnapshotWithError(pageSnapshot);
}
});
return false;
});
function updatePageJumpStepperState(input) {
const value = Number(input.value);
const min = Number(input.min);
const max = Number(input.max);
const $stepper = $(input).closest('.page-jump-input-wrap');
$stepper.find('.page-jump-step-up').prop('disabled', Number.isFinite(value) && value >= max);
$stepper.find('.page-jump-step-down').prop('disabled', !Number.isFinite(value) || value <= min);
}
function validatePageJumpInput(input, notify) {
const value = input.value.trim();
const min = input.min === '' ? null : Number(input.min);
const max = input.max === '' ? null : Number(input.max);
const page = Number(value);
let message = '';
if (!value) {
message = '请输入页码';
} else if (!Number.isInteger(page)) {
message = '请输入有效页码';
} else if (Number.isFinite(min) && page < min) {
message = `页码不能小于 ${min}`;
} else if (Number.isFinite(max) && page > max) {
message = `页码不能大于 ${max}`;
}
const wasInvalid = input.dataset.pageJumpInvalid === 'true';
input.setCustomValidity(message);
input.dataset.pageJumpInvalid = message ? 'true' : 'false';
if (notify && message && message !== '请输入页码' && !wasInvalid
&& window.cocoMessage && typeof window.cocoMessage.warning === 'function') {
window.cocoMessage.warning(message);
}
return !message;
}
function stepPageJumpInput(input, direction) {
const min = Number(input.min);
const max = Number(input.max);
const step = Number(input.step) > 0 ? Number(input.step) : 1;
const current = Number(input.value);
const value = Number.isFinite(current) ? current + direction * step : min;
input.value = String(Math.min(max, Math.max(min, value)));
input.dispatchEvent(new Event('input', { bubbles: true }));
input.focus();
}
function initPageJumpSteppers() {
$('.page-jump-input').each(function () {
updatePageJumpStepperState(this);
});
}
$(document).on('click', '.page-jump-step', function (event) {
event.preventDefault();
if (this.disabled) return;
const input = $(this).closest('.page-jump-input-wrap').find('.page-jump-input')[0];
if (input) {
stepPageJumpInput(input, $(this).hasClass('page-jump-step-up') ? 1 : -1);
}
});
$(document).on('keydown', '.page-jump-input', function (event) {
if (event.ctrlKey || event.metaKey || event.altKey) return;
const allowedKeys = ['Backspace', 'Delete', 'Tab', 'Enter', 'Escape', 'ArrowLeft', 'ArrowRight', 'Home', 'End'];
if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
event.preventDefault();
stepPageJumpInput(this, event.key === 'ArrowUp' ? 1 : -1);
return;
}
if (!allowedKeys.includes(event.key) && !/^[0-9]$/.test(event.key)) {
event.preventDefault();
}
});
$(document).on('input', '.page-jump-input', function () {
this.value = this.value.replace(/[^0-9]/g, '').replace(/^0+(?=\d)/, '');
validatePageJumpInput(this, true);
updatePageJumpStepperState(this);
});
// 跳转到指定页:沿用当前 URL 的分类或标签参数,通过 PJAX 加载目标页。
$(document).on('submit', '.page-jump-form', function (event) {
event.preventDefault();
const $form = $(this);
const input = $form.find('.page-jump-input')[0];
validatePageJumpInput(input, true);
if (!this.checkValidity()) {
input.focus();
if (typeof input.reportValidity === 'function') input.reportValidity();
return false;
}
const targetPage = parseInt($form.find('.page-jump-input').val(), 10);
const href = buildPageUrlFromCurrent(targetPage);
if (window.pjax && typeof window.pjax.loadUrl === 'function') {
window.pjax.loadUrl(href);
} else {
window.location.assign(href);
}
return false;
});
//ajax加载片刻
$(document).on('click', '#t_pagination a', function () {
var href = $(this).attr('data');
const currentPage = getPageNumberFromUrl(href);
const $pagingArea = $('#t_pagination .post-paging');
const pageSnapshot = createAjaxPageSnapshot({ $pagingArea: $pagingArea });
$.ajax({
type: "GET",
url: href,
headers: HTML_PAGE_AJAX_HEADERS,
beforeSend: function () {
$('#t_pagination .post-paging').html('');
},
success: function (posts) {
if (posts) {
var result = $(posts).find(".moment_list .p_item");
$(".moment_list").append(result.fadeIn(300));
refreshAjaxPostList();
updateLoadMorePagination('#t_pagination', '.moment_list', posts);
if (result.length) {
$body.animate({ scrollTop: result.first().offset().top - 58 }, 500);
}
getMomentAudio();
initAgree();
if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update();
initializeMomentFold();
initDoubanDetailLinks();
syncPageParamToUrl(currentPage);
} else {
$('#t_pagination a').hide();
}
},
error: function () {
restorePagingSnapshotWithError(pageSnapshot);
}
});
return false;
});
// AJAX分类切换图库
$(document).ready(function () {
$(document).on('click', '.photos_cat_nav ul li a', function (e) {
var $this = $(this);
if ($this.hasClass('disabled') || $this.hasClass('active')) {
return false;
}
var url = $this.data('href');
if (!url) {
return false;
}
var displayUrl = removePageParamFromUrl(url);
// page 参数现在统一通过 removePageParamFromUrl 清理。
/*
try {
var photoUrl = new URL(url, window.location.origin);
photoUrl.searchParams.delete('page');
displayUrl = decodeURI(photoUrl.pathname + photoUrl.search + photoUrl.hash);
} catch (e) { }
*/
$('.photos_cat_nav ul li a').addClass('disabled');
// --- 1. 保存旧内容 (关键修改) ---
var $photosItem = $("#photos_item");
var pageSnapshot = createAjaxPageSnapshot({
$content: $photosItem,
paginationSelector: '#p_pagination'
});
$photosItem.empty();
$('#p_pagination a').hide();
$.ajax({
type: "GET",
url: url,
headers: HTML_PAGE_AJAX_HEADERS,
beforeSend: function () {
showListLoading("#photos_item", PHOTO_LIST_LOADING_HTML);
hidePagination('#p_pagination');
},
success: function (data) {
setCategoryLinkActive($this);
var $data = $(data);
var newContent = $data.find("#photos_item").html();
$("#photos_item").html(newContent);
updateLoadMorePagination('#p_pagination', '#photos_item', data);
if (typeof pix !== 'undefined' && pix.initGalleryPhotos) {
pix.initGalleryPhotos();
}
if (typeof lazyLoadInstance !== 'undefined') {
lazyLoadInstance.update();
}
if ($('.gallery-photos').length > 0 && typeof waterfall === 'function') {
waterfall('.gallery-photos');
}
$('.photos_cat_nav ul li a').removeClass('disabled');
history.replaceState({ path: displayUrl }, '', displayUrl);
},
error: function () {
restoreAjaxSnapshotWithError(pageSnapshot);
$('.photos_cat_nav ul li a').removeClass('disabled');
}
});
return false;
});
});
//ajax加载图库
$(document).on('click', '#p_pagination a', function () {
var href = $(this).attr('data');
const currentPage = getPageNumberFromUrl(href);
const $pagingArea = $('#p_pagination .post-paging');
const pageSnapshot = createAjaxPageSnapshot({ $pagingArea: $pagingArea });
const targetOffsetTop = $('#p_pagination a').offset().top;
$.ajax({
type: "GET",
url: href,
headers: HTML_PAGE_AJAX_HEADERS,
beforeSend: function () {
$('#p_pagination .post-paging').html('');
},
success: function (photos) {
if (photos) {
var result = $(photos).find(".norpost_list .gallery-photo");
$(".gallery-photos").append(result.fadeIn(300));
updateLoadMorePagination('#p_pagination', '#photos_item', photos);
$body.animate({ scrollTop: targetOffsetTop - 358 }, 500);
pix.initGalleryPhotos();
if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update();
syncPageParamToUrl(currentPage);
} else {
$('#p_pagination a').hide();
}
},
error: function () {
restorePagingSnapshotWithError(pageSnapshot);
}
});
return false;
});
//阅读更多按钮
$(document).on('click', 'a.show-more-btn', function () {
var t = $(this);
t.prev().show();
t.next().show();
t.siblings('.dotd').hide();
t.hide();
});
$(document).on('click', 'a.read-less-btn', function () {
var t = $(this);
t.siblings('.rm_hidden').hide();
t.siblings('.dotd').show();
t.prev().show();
t.hide();
});
//ajax加载评论
$(document).on('click', '.show_comment', function () {
$('.blog_list_inner').css('min-height', 'calc(100vh)');
var pid = $(this).attr('pid');
var other = $(this).parents('.moment_item').siblings('div');
$.each(other, function (name, value) {
//遍历每个 回复表单
var otherid = $(this).find('.show_comment').attr('pid');
$("#halo-comment-" + otherid).hide();
});
$(`#halo-comment-${pid}`).css('display', $(`#halo-comment-${pid}`).css('display') == 'block' ? 'none' : 'block');
});
//片刻点赞
$(document).on('click', '.up_like ', function () {
if ($(this).hasClass('done')) {
cocoMessage.info("地久天长");
return false;
} else {
$(this).addClass('done');
var pid = $(this).data("id");
var key = $(this).data("key");
let agreeArr = localStorage.getItem(`pix.upvoted.${key}.names`)
? JSON.parse(localStorage.getItem(`pix.upvoted.${key}.names`))
: [];
rateHolder = $(this).children('span');
iconHolder = $(this).children('i');
$.ajax({
type: 'post',
contentType: "application/json; charset=utf-8",
url: '/apis/api.halo.run/v1alpha1/trackers/upvote',
data: JSON.stringify({
group: key == "moment" ? "moment.halo.run" : "content.halo.run",
plural: key == "moment" ? "moments" : "posts",
name: pid,
}),
success: function (data) {
$(iconHolder).toggleClass('ri-heart-2-fill');
var num = $(rateHolder).text();
$(rateHolder).text(++num);
agreeArr.push(pid);
const val = JSON.stringify(agreeArr);
localStorage.setItem(`pix.upvoted.${key}.names`, val);
cocoMessage.success("卿卿与黄");
}
}); // end ajax
}
});
function initAgree() {
var agreeAnnius = $('.up_like')
if (agreeAnnius.length > 0) {
let agreeArr = JSON.parse(localStorage.getItem(`pix.upvoted.${$(agreeAnnius[0]).data("key")}.names`))
for (var i = 0; i < agreeAnnius.length; i++) {
let pid = $(agreeAnnius[i]).attr('data-id');
if (agreeArr != null) {
let flag = agreeArr.includes(pid);
if (flag) {
$(agreeAnnius[i]).addClass('done');
}
}
}
}
}
function getMomentAudio() {
var audioList = $('.pix_player.qt')
if (audioList.length > 0) {
for (var i = 0; i < audioList.length; i++) {
let id = $(audioList[i]).attr('id');
let type = $(audioList[i]).attr('type');
var result = type.substring(type.indexOf("audio/") + 6);
if (id != null && id != '') {
var api = `${Theme.play.pix_mu_api || 'https://api.i-meto.com/meting/api'}?type=song&id=:id`
var meta = {
type: result,
id: id,
}
let url = api.replace(":id", meta.id);
$.ajax({
type: "get",
url: url,
success: function (res) {
var html = ''
if (res.length > 0) {
let author = res[0].author;
let pic = res[0].pic;
let title = res[0].title;
let url = res[0].url;
let lrc = res[0].lrc;
html = `
`;
} else {
html = '音乐参数错误';
}
$('#' + id).html(html);
}
});
}
}
}
}
// ajax分类筛选 posts(首页片刻时改这个)
$(document).on('click', '.posts_cat_nav ul li a', function (e) {
e.preventDefault();
var $this = $(this);
var t = $('.posts_cat_nav ul li a');
if (t.hasClass('disabled')) {
return false;
}
$('.posts_cat_nav ul li a').addClass('disabled');
// --- 1. 保存旧内容---
var $momentList = $(".norpost_list");
var pageSnapshot = createAjaxPageSnapshot({
$content: $momentList,
paginationSelector: '#pagination'
});
$(".norpost_list").empty();
$('#pagination a').hide();
var cat = $(this).attr('data');
// 替换:获取a标签内的中文文本并去除空格
var tag = $(this).text().trim();
var displayUrl = '/archives';
try {
const archiveUrl = new URL(cat, window.location.origin);
archiveUrl.searchParams.delete('page');
if (archiveUrl.pathname === '/archives') {
displayUrl = decodeURI(archiveUrl.pathname + archiveUrl.search + archiveUrl.hash);
} else if (tag !== '全部' && tag !== '') {
displayUrl = '/archives?tag=' + encodeURIComponent(tag);
}
} catch (e) {
if (tag !== '全部' && tag !== '') {
displayUrl = '/archives?tag=' + encodeURIComponent(tag);
}
}
displayUrl = removePageParamFromUrl(displayUrl);
$.ajax({
type: "GET",
url: cat, // 完全保留原有请求URL,不修改
headers: HTML_PAGE_AJAX_HEADERS,
beforeSend: function () {
showListLoading('.norpost_list');
hidePagination('#pagination');
},
success: function (data) {
setCategoryLinkActive($this);
$('#pagination a').text(Theme.site_page);
var result = $(data).find(".norpost_list").children();
$(".norpost_list").append(result.fadeIn(300));
refreshAjaxPostList();
updateLoadMorePagination('#pagination', '.norpost_list', data, '.arc_pagenav');
$('.norpost_list .loading_box').remove();
initAgree();
lazyLoadInstance.update();
$('.posts_cat_nav ul li a').removeClass('disabled');
history.replaceState({ url: displayUrl }, '', displayUrl);
},
error: function () {
$('.posts_cat_nav ul li a').removeClass('disabled');
restoreAjaxSnapshotWithError(pageSnapshot);
}
});
});
//ajax加载文章
$('body').on('click', '#pagination a', function () {
const $pagingArea = $('#pagination .post-paging');
const pageSnapshot = createAjaxPageSnapshot({ $pagingArea: $pagingArea });
var href = $(this).attr('data');
const currentPage = getPageNumberFromUrl(href);
$.ajax({
type: "GET",
url: href,
headers: HTML_PAGE_AJAX_HEADERS,
beforeSend: function () {
$('#pagination .post-paging').html('');
},
success: function (data) {
if (data) {
var result = $(data).find(".norpost_list ").children();
$('.norpost_list').append($(result).fadeIn(400));
refreshAjaxPostList();
updateLoadMorePagination('#pagination', '.norpost_list', data, '.arc_pagenav');
if (result.length) {
$body.animate({ scrollTop: result.first().offset().top - 58 }, 500);
}
initAgree()
if (typeof lazyLoadInstance !== 'undefined') lazyLoadInstance.update();
syncPageParamToUrl(currentPage);
} else {
$("#pagination a").hide();
}
},
error: function () {
restorePagingSnapshotWithError(pageSnapshot);
}
});
return false;
});
// ajax加载分类页面文章
$('body').on('click', '.arc_pagenav a', function () {
// 【新增】保存分页区域的原始HTML,用于失败时恢复
const $pagingArea = $('.arc_pagenav');
const pageSnapshot = createAjaxPageSnapshot({ $pagingArea: $pagingArea });
var href = $(this).attr('data');
const currentPage = getPageNumberFromUrl(href);
$(this).hide();
var content = $('.norpost_list');
if (href != undefined) {
$.ajax({
type: "GET",
url: href,
headers: HTML_PAGE_AJAX_HEADERS,
beforeSend: function () {
$('.arc_pagenav').append('');
},
success: function (data) {
var post = $(data).find(".norpost_list").children();
content.append(post.fadeIn(300));
refreshAjaxPostList();
var newhref = $(data).find(".arc_pagenav a").attr("data"); //找出新的下一页链接
if (newhref != undefined) {
$(".arc_pagenav a").attr("data", newhref);
$('.arc_pagenav a').show();
} else {
$(".arc_pagenav a").hide(); //如果没有下一页了,隐藏
}
$('.arc_pagenav .uk-spinner').remove();
$body.animate({ scrollTop: post.offset().top - 58 }, 500);
initAgree()
lazyLoadInstance.update();
syncPageParamToUrl(currentPage);
},
error: function () {
restorePagingSnapshotWithError(pageSnapshot);
}
});
}
return false;
});
function loginUrl() {
window.location.href = `/login?redirect_uri=${encodeURIComponent(window.location.pathname)}`;
}
$(document).on('mouseenter', '.lbc .left_menu_box ul li a , body.mod_third_s .left_menu_box ul li a', function (event) {
var title = $(this).find('.nav_title').text();
$(this).append("");
});
$(document).on('mouseleave', '.lbc .left_menu_box ul li a , body.mod_third_s .left_menu_box ul li a', function (event) {
$(this).find('.menu_tips').remove();
});
//滚动
$(document).ready(function (e) {
$(window).scroll(function () {
var b = $(window).scrollTop(); //监控窗口已滚动的距离;
if (b > 190) {
$('.top_bar').addClass('mobile_active');
} else {
$('.top_bar').removeClass('mobile_active');
}
if (b > 1500) {
$('a.go_top').addClass('show');
$('a.tool_top').addClass('show');
} else {
$('a.go_top').removeClass('show');
$('a.tool_top').removeClass('show');
}
});
});
$.fn.autoTextarea = function (options) {
var defaults = {
maxHeight: null,//文本框是否自动撑高,默认:null,不自动撑高;如果自动撑高必须输入数值,该值作为文本框自动撑高的最大高度
minHeight: 50
};
var opts = $.extend({}, defaults, options);
return $(this).each(function () {
$(this).bind("paste cut keydown keyup focus blur", function () {
var height, style = this.style;
this.style.height = opts.minHeight + 'px';
if (this.scrollHeight > opts.minHeight) {
if (opts.maxHeight && this.scrollHeight > opts.maxHeight) {
height = opts.maxHeight;
style.overflowY = 'scroll';
} else {
height = this.scrollHeight;
style.overflowY = 'hidden';
}
style.height = height + 'px';
}
});
});
};
$('body').on('click', '.com_msg_btn', function () {
var num = $(this).attr('check');
if (num == 0) {
return false;
}
$.ajax({
type: 'POST',
dataType: 'json',
url: Theme.ajaxurl,
data: {
'action': 'up_unread_msg',
},
beforeSend: function () {
},
success: function (data) {
if (data.code == '0') {
$('small.f_unread_num').remove();
} else {
return false;
}
}
});
});
//搜索类型
$('body').on('click', '.s_set_box a', function () {
var type = $(this).attr('data');
$(this).addClass('active').siblings('a').removeClass('active');
$('form#index_search input[type="hidden"]').val(type);
$.cookie('s_type', type, { expires: 30, path: '/' });
});
$('body').on('click', '.top_s_box a', function () {
UIkit.dropdown('.s_set_box').hide(false);
var data = $(this).attr('data');
var type = $(this).text();
$('.set_text').text(type);
$('form#top_search input[type="hidden"]').val(data);
});
//黑暗模式
$('body').on('click', '.t_dark a', function () {
var t = $('html');
if (t.hasClass('dark')) {
$.cookie('dark', 'normal', { path: '/', expires: 30 });
} else {
$.cookie('dark', 'dark', { path: '/', expires: 30 });
}
t.toggleClass('dark');
});
//片刻管理按钮
$(document).on('mouseenter', '.post_control_btn', function (event) {
var a = $(this).siblings('.post_control_box');
a.addClass('show');
});
$(document).on('mouseleave', '.post_control', function (event) {
$(this).find('.post_control_box').removeClass('show');
});
//社交小工具二维码
$(document).on('mouseenter', '.sw_social', function (event) {
var qrbox = $(this).siblings('.sw_qrcode');
if (qrbox.length > 0) {
qrbox.addClass('active');
qrbox.fadeIn(200);
}
});
$(document).on('mouseleave', '.sw_social', function (event) {
var qrbox = $(this).siblings('.sw_qrcode');
if (qrbox.length > 0) {
qrbox.removeClass('active');
qrbox.fadeOut(200);
}
});
//点击收起移动侧栏
$('body').on('click', '.m_offcanvas', function () {
var target = event.target;
var parentAnchor = $(target).closest('a');
if (target.getAttribute('href') == '#' || parentAnchor.attr('href') == '#') {
} else {
UIkit.offcanvas('.m_offcanvas').hide();
}
});
// 刷新内容(兼容一言和今日诗词API)
let yiyanLoading = false; // 标志是否正在请求
$('body').on('click', '.yiyan_box .change', function () {
// 若请求还未恢复消息,直接return
if (yiyanLoading) {
return;
}
yiyanLoading = true; // 设置请求开始标志
var url = Theme.widget_yiyan.api || 'https://v1.hitokoto.cn';
fetch(url)
.then(response => response.json())
.then(data => {
const targetElement = document.querySelector('.yiyan_box p');
if (url.includes('api.anian.net')) {
// 新增处理逻辑
targetElement.innerText = data.content || '一日不见如隔三秋';
const tooltipTitle = data.title || '失败:超时或发生错误';
targetElement.setAttribute("uk-tooltip", tooltipTitle === '失败:超时或发生错误' ? `${tooltipTitle}${data.author || ''}` : `《${tooltipTitle}》${data.author || ''}`);
} else {
// 原有一言API处理逻辑
targetElement.innerText = data.hitokoto || '一日不见如隔三秋';
targetElement.setAttribute("uk-tooltip", data.from || '失败:超时或发生错误');
}
})
.finally(() => {
yiyanLoading = false; // 请求完成,重置标志
})
});
$('.yiyan_box .change').click();
//pjax
$(document).on('pjax:error', function (event, xhr, textStatus, errorThrown, options) {
cocoMessage.error('加载失败!');
});
if (Theme.pjax) {
let pjaxSelectors = ["head title", "#pjax-container", ".pjax"]
var pjax = new Pjax({
elements: 'a:not([target="_blank"]):not([pjax="exclude"])',
selectors: pjaxSelectors,
analytics: false,
cacheBust: false,
});
document.addEventListener('pjax:send', function () {
NProgress.start();
})
document.addEventListener('pjax:complete', function () {
lazyLoadInstance.update();
typeof hljs === 'object' && hljs.highlightAll();
typeof Prism === 'object' && Prism.highlightAll();
autoload_posts_music();
initBlog();
initPageJumpSteppers();
refreshCommentWidget();
NProgress.done();
initPreviousPageButton()
})
}
// 刷新评论组件函数
function refreshCommentWidget() {
const commentWrappers = document.querySelectorAll('.halo-comment');
if (commentWrappers.length > 0) {
commentWrappers.forEach(wrapper => {
const scripts = wrapper.querySelectorAll('script[type="module"]');
scripts.forEach(oldScript => {
const newScript = document.createElement('script');
newScript.type = 'module';
// 复制所有属性
Array.from(oldScript.attributes).forEach(attr => {
if (attr.name !== 'type') {
newScript.setAttribute(attr.name, attr.value);
}
});
// 复制脚本内容
newScript.textContent = oldScript.textContent;
// 替换旧脚本
oldScript.parentNode.insertBefore(newScript, oldScript);
oldScript.remove();
});
});
}
}
$('body').on('click', '.msg_modal_inner .unread_box .box .mark_read', function (e) {
let msg_name = $(this).parent()[0].getAttribute('msg-name')
let username = Theme.username
$.ajax({
type: "put",
url: `/apis/api.notification.halo.run/v1alpha1/userspaces/${username}/notifications/${msg_name}/mark-as-read`,
success: function (res) {
pix.getMsg()
}
});
})
const getWindowInfo = () => {
pix.initTopBar()
};
const debounce = (fn, delay) => {
let timer;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn();
}, delay);
}
};
const cancalDebounce = debounce(getWindowInfo, 1);
window.addEventListener('resize', cancalDebounce);
//固定顶部栏
$(document).scroll(function () {
let topBar = $('#masthead .top_bar');
var placeholder = document.querySelector('#masthead .uk-sticky-placeholder');
var width = topBar.width();
var scrT = document.documentElement.scrollTop;
if (window.innerWidth > 960) {
// 如果滚动的距离>60
if (scrT > 60) {
topBar.addClass('uk-active uk-sticky-fixed').css({ "width": width, "top": '0px', "position": "fixed" });
placeholder.hidden = false;
} else {
topBar.removeClass('uk-active uk-sticky-fixed').css({ "width": "auto", "top": "auto", "position": "" });
placeholder.hidden = true;
}
} else {
// 如果滚动的距离>0
if (scrT > 0) {
topBar.addClass('uk-active uk-sticky-below')
} else {
topBar.removeClass('uk-active uk-sticky-below')
}
}
});
$('body').on('click', '.listree-btn', function (event) {
event.preventDefault();
setListreeOpen(!$('.listree-box').hasClass('is-open'));
return false;
});
$(document).on('click.listreeOutside', function (event) {
if (!$('body').hasClass('toc-open')) return;
if ($(event.target).closest('.listree-box, .toc_nav').length) return;
setListreeOpen(false);
});
$(document).on('keydown.listree', function (event) {
if (event.key === 'Escape') {
setListreeOpen(false);
}
});
function resetListree() {
$('body').removeClass('toc-ready toc-open');
$('.toc_nav').attr('aria-hidden', 'true');
$('.listree-btn')
.removeClass('is-active')
.attr({
'title': '展开目录',
'aria-label': '展开目录',
'aria-expanded': 'false'
});
$('.listree-box')
.removeClass('is-open')
.attr('aria-hidden', 'true');
}
function setListreeOpen(open) {
if (open && !$('body').hasClass('toc-ready')) return;
$('body').toggleClass('toc-open', open);
$('.listree-box')
.toggleClass('is-open', open)
.attr('aria-hidden', open ? 'false' : 'true');
$('.listree-btn')
.toggleClass('is-active', open)
.attr({
'title': open ? '收起目录' : '展开目录',
'aria-label': open ? '收起目录' : '展开目录',
'aria-expanded': open ? 'true' : 'false'
});
}
// toc
function autotree() {
$(document).ready(function () {
resetListree();
$('#listree-ol').empty().hide();
// 获取所有标题元素
var headings = document.querySelectorAll('.post-single .single-content *:is(h1, h2, h3, h4, h5, h6)');
var tocList = document.querySelector('#listree-ol');
if (!tocList || headings.length < 1) {
$(window).off('scroll.listree resize.listree');
return;
}
// 保存每个级别的父列表项
var parentItems = {};
// 遍历每个标题元素
headings.forEach(function (heading, index) {
heading.classList.add('listree-list');
heading.id = 'listree-list' + index;
var level = parseInt(heading.tagName.slice(1));
var listItem = document.createElement('li');
var link = document.createElement('a');
var parentItem = null;
listItem.setAttribute('data-level', level);
listItem.style.setProperty('--toc-index', index);
link.href = '#listree-list' + index;
link.classList.add('toc-link', 'node-name--' + heading.tagName);
link.textContent = heading.textContent.trim();
listItem.appendChild(link);
for (var parentLevel = level - 1; parentLevel >= 1; parentLevel--) {
if (parentItems[parentLevel]) {
parentItem = parentItems[parentLevel];
break;
}
}
if (parentItem) {
if (!parentItem.querySelector('ul')) {
parentItem.appendChild(document.createElement('ul'));
}
parentItem.querySelector('ul').appendChild(listItem);
} else {
tocList.appendChild(listItem);
}
parentItems[level] = listItem;
Object.keys(parentItems).forEach(function (key) {
if (parseInt(key) > level) {
delete parentItems[key];
}
});
});
$('body').addClass('toc-ready');
$('.toc_nav').attr('aria-hidden', 'false');
$('#listree-ol').show();
$('body').off('click.listreeLink', 'a.toc-link').on('click.listreeLink', 'a.toc-link', function (event) {
event.preventDefault();
var targetId = $(this).attr("href");
var $target = $(targetId);
if (!$target.length) return;
$("html, body").animate({
scrollTop: $target.offset().top - 77
}, 500);
if (window.innerWidth <= 768) {
setListreeOpen(false);
}
});
})
jQuery(document).ready(function (f) {
var T = f(".listree-list");
if (T.length < 1)
return;
var b = [];
function Q() {
b = [];
T.each(function () {
var T = f(this).offset();
b.push(Math.floor(T.top))
})
}
function a(T) {
var b = f("#listree-ol li");
if (b.length < 1)
return;
if (!b.eq(T).hasClass("current")) {
b.removeClass("current");
b.eq(T).addClass("current");
}
}
function X() {
if ($('#listree-ol').children().length < 1)
return;
var f = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
var Q = Math.ceil(f + 77);
var X = 0;
for (var aU = 0; aU < b.length; aU++) {
if (Q >= b[aU]) {
X = aU
} else {
break
}
}
if (X < 0)
X = 0;
if (!T.eq(X).hasClass("current")) {
T.removeClass("current");
T.eq(X).addClass("current");
a(X)
}
}
Q();
setTimeout(X, 0);
f(window).off('scroll.listree resize.listree').on('scroll.listree', X).on('resize.listree', function () {
Q();
X();
})
});
}
pix.addRuntime();
$(document).ready(function () {
$("[data-fancybox]").fancybox({
selector: '[data-fancybox]',
loop: true,
transitionEffect: 'slide',
protect: true,
buttons: ['slideShow', 'fullScreen', 'thumbs', 'close'],
hash: false
})
})
// 手机端底部菜单高亮
function highlightActiveMenu() {
let currentPath = window.location.pathname.replace(/\/+$/, "");
const pathParts = currentPath.split('/');
let firstLevelPath = '/' + (pathParts[1] || '');
if (firstLevelPath === '/') currentPath = '/';
const menuRules = {
diary: ['/', '/moments'],
composition: ['/content', '/categories', '/tags', '/archives'],
appendix: []
};
const footerMenu = document.querySelector('.footer_menu');
if (!footerMenu) return;
const diaryLi = footerMenu.querySelector('a[href="/"]').closest('li');
const compositionLi = footerMenu.querySelector('a[href="/archives"]').closest('li');
const appendixLi = footerMenu.querySelector('a[href="/navigator"]').closest('li');
const allMenuLis = footerMenu.querySelectorAll('.item li');
allMenuLis.forEach(li => {
li.classList.remove('active');
const link = li.querySelector('a');
if (link) {
link.classList.remove('active');
link.style.color = "";
const icon = link.querySelector("i");
if (icon) icon.style.color = "";
}
});
const highlightMenu = (menuLi) => {
if (!menuLi) return;
const link = menuLi.querySelector('a');
menuLi.classList.add('active');
link.classList.add('active');
link.style.color = "#4CAF50";
const icon = link.querySelector("i");
if (icon) icon.style.color = "#4CAF50";
};
if (menuRules.diary.includes(firstLevelPath)) {
highlightMenu(diaryLi);
}
else if (menuRules.composition.includes(firstLevelPath)) {
highlightMenu(compositionLi);
}
else {
highlightMenu(appendixLi);
}
}
// 指定日期黑白效果
function setPageGrayscale() {
const dateList = ['12-13'];
const style = document.createElement('style');
style.innerHTML = '.grayscale-mode{filter:grayscale(100%)!important;-webkit-filter:grayscale(100%)!important;transition:filter 60s ease!important;}';
document.head.appendChild(style);
const today = new Date();
const todayMd = `${today.getMonth() + 1}-${today.getDate()}`;
if (dateList.includes(todayMd)) {
document.documentElement.classList.add('grayscale-mode');
}
}
// 内容折叠初始化
function initializeMomentFold() {
const foldConfig = {
maxHeight: 240,
moreText: '展开',
lessText: '收起'
};
$('.moment-collapse-container').each(function () {
const $contentContainer = $(this);
if ($contentContainer.next('.moment-fold-btn').length > 0) return;
// 完整内容高度
const fullHeight = $contentContainer[0].scrollHeight;
const needFold = fullHeight > foldConfig.maxHeight;
if (!needFold) return;
// 初始化折叠状态
$contentContainer.addClass('collapsed').css('max-height', foldConfig.maxHeight + 'px');
const $foldBtn = $(``);
$contentContainer.after($foldBtn);
// 折叠/展开切换
$foldBtn.on('click', function () {
const isCollapsed = $contentContainer.hasClass('collapsed');
const heightDiff = fullHeight - foldConfig.maxHeight; // 完整高度与折叠高度的差值
if (isCollapsed) {
// 展开逻辑
$contentContainer.removeClass('collapsed').css('max-height', fullHeight + 'px');
$(this).text(foldConfig.lessText);
} else {
// 收起逻辑:页面向下滚动差值距离
$('html, body').animate({ scrollTop: $(window).scrollTop() - heightDiff }, 300, 'linear');
$contentContainer.addClass('collapsed').css('max-height', foldConfig.maxHeight + 'px');
$(this).text(foldConfig.moreText);
}
});
});
}
// 更换背景函数封装
function setFixedBackground(bgImageUrl) {
const body = document.body;
const requestId = (Number(body.dataset.backgroundRequestId) || 0) + 1;
body.dataset.backgroundRequestId = requestId;
// 传入空值时淡出并清除当前背景。
if (bgImageUrl == null || String(bgImageUrl).trim().toLowerCase() === 'null' || String(bgImageUrl).trim() === '') {
body.querySelectorAll('.fixed-background-layer').forEach((layer) => {
layer.classList.remove('is-visible');
setTimeout(() => layer.remove(), 650);
});
body.classList.remove('common-fixed-bg');
return;
}
const image = new Image();
image.onload = async () => {
if (typeof image.decode === 'function') {
try { await image.decode(); } catch (_) { }
}
if (body.dataset.backgroundRequestId !== String(requestId)) return;
const backgroundLayer = document.createElement('div');
backgroundLayer.className = 'fixed-background-layer';
backgroundLayer.style.backgroundImage = `url('${bgImageUrl}')`;
body.appendChild(backgroundLayer);
// 先应用透明状态,再切换到可见状态,确保每次调用都触发淡入。
backgroundLayer.offsetWidth;
requestAnimationFrame(() => backgroundLayer.classList.add('is-visible'));
body.querySelectorAll('.fixed-background-layer:not(:last-child)').forEach((layer) => {
layer.classList.remove('is-visible');
setTimeout(() => layer.remove(), 650);
});
};
body.classList.add('common-fixed-bg');
image.src = bgImageUrl;
}
// 奇遇显示函数封装
function showCenterImage(imageUrl, duration = 2000) {
const container = document.getElementById('centerImgContainer');
const img = document.getElementById('targetImg');
// 清理上一次调用遗留的自动关闭定时器。
clearTimeout(container._centerImageCloseTimer);
clearTimeout(container._centerImageResetTimer);
// 重置所有状态(避免上一次操作残留影响)
container.classList.remove('container-fade-active');
img.classList.remove('img-fade-in', 'img-fade-out');
img.style.opacity = 0;
img.src = ""; // 先清空原有src
// 定义图片加载成功的回调函数
function handleImageLoad() {
// 移除事件监听(防止重复绑定)
img.removeEventListener('load', handleImageLoad);
img.removeEventListener('error', handleImageError);
// 图片加载成功后,再执行淡入动画
container.classList.add('container-fade-active');
img.classList.add('img-fade-in');
// duration 为 0 时保持显示,不执行自动关闭逻辑。
if (duration <= 0) return;
container._centerImageCloseTimer = setTimeout(() => {
container.classList.remove('container-fade-active');
img.classList.add('img-fade-out');
container._centerImageResetTimer = setTimeout(() => {
img.classList.remove('img-fade-in', 'img-fade-out');
}, 500);
}, duration);
}
// 定义图片加载失败的回调函数
function handleImageError() {
// 移除事件监听
img.removeEventListener('load', handleImageLoad);
img.removeEventListener('error', handleImageError);
// 重置容器和图片状态,不执行任何动画
container.classList.remove('container-fade-active');
img.classList.remove('img-fade-in', 'img-fade-out');
img.style.opacity = 0;
img.src = "";
}
// 绑定图片加载/失败事件监听(先绑定,再赋值src,避免缓存导致回调不触发)
img.addEventListener('load', handleImageLoad);
img.addEventListener('error', handleImageError);
// 最后赋值src,触发图片加载(异步操作)
img.src = imageUrl;
}
// 侧边栏农历信息显示函数
function anian_renderLunarUI() {
const textEl = document.getElementById('anianLunarText');
if (!textEl) return;
const doRender = (data) => {
if (!data) {
textEl.innerHTML = '一日不见 · 如隔三秋';
return;
}
const { ganzhiYear = '', lunarMonth = '', lunarDay = '', jieqi = '', jijie = '', traditionalFestival = '', shengxiao = '' } = data;
let text = `${ganzhiYear}${shengxiao}年 · ${lunarMonth}月${lunarDay}`;
const extra = [];
if (jieqi) extra.push(jieqi);
if (traditionalFestival) extra.push(traditionalFestival);
if (extra.length) text += `
${extra.join(' · ')}`;
textEl.innerHTML = text;
if (jieqi) showCenterImage('/upload/' + jieqi + '.webp');
// setFixedBackground('/upload/JX3WJ.mp4_20260207_022345.027.jpg');
};
const tryRender = (attempt) => {
let data = null;
try {
const cookieVal = $.cookie('anian_lunar_info');
if (cookieVal) data = JSON.parse(cookieVal);
} catch (_) { }
if (data) {
doRender(data);
} else if (attempt < 20) {
setTimeout(() => tryRender(attempt + 1), 500);
} else {
doRender(null);
}
};
tryRender(0);
}
// 绿色数字时钟粒子效果
function initGreenDigitalClock() {
var t = 820;
var a = 250;
var r = 7;
var n = 10;
var e = .65;
var f;
var o = [];
const v = ["#00FF7F", "#32CD32", "#228B22", "#008000", "#006400", "#90EE90", "#98FB98", "#00FA9A", "#00FF00", "#3CB371"];
var h = [];
var u = [
[[0, 0, 1, 1, 1, 0, 0], [0, 1, 1, 0, 1, 1, 0], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [0, 1, 1, 0, 1, 1, 0], [0, 0, 1, 1, 1, 0, 0]],
[[0, 0, 0, 1, 1, 0, 0], [0, 1, 1, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0], [1, 1, 1, 1, 1, 1, 1]],
[[0, 1, 1, 1, 1, 1, 0], [1, 1, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 1, 1, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1]],
[[1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0, 0], [0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [0, 1, 1, 1, 1, 1, 0]],
[[0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 1, 1, 1, 0], [0, 0, 1, 1, 1, 1, 0], [0, 1, 1, 0, 1, 1, 0], [1, 1, 0, 0, 1, 1, 0], [1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 1, 1, 1, 1]],
[[1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [0, 1, 1, 1, 1, 1, 0]],
[[0, 0, 0, 0, 1, 1, 0], [0, 0, 1, 1, 0, 0, 0], [0, 1, 1, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 1, 1, 1, 0], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [0, 1, 1, 1, 1, 1, 0]],
[[1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 1, 1], [0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 0, 1, 1, 0, 0], [0, 0, 1, 1, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0], [0, 0, 1, 1, 0, 0, 0]],
[[0, 1, 1, 1, 1, 1, 0], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [0, 1, 1, 1, 1, 1, 0], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [0, 1, 1, 1, 1, 1, 0]],
[[0, 1, 1, 1, 1, 1, 0], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [0, 1, 1, 1, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 1, 1, 0, 0], [0, 1, 1, 0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
];
function l(t) {
var a = [];
f.fillStyle = "#006400";
var r = new Date;
var e = 70, o = 30;
var v = r.getHours();
var u = Math.floor(v / 10);
var l = v % 10;
a.push({ num: u });
a.push({ num: l });
a.push({ num: 10 });
var c = r.getMinutes();
var u = Math.floor(c / 10);
var l = c % 10;
a.push({ num: u });
a.push({ num: l });
a.push({ num: 10 });
var M = r.getSeconds();
var u = Math.floor(M / 10);
var l = M % 10;
a.push({ num: u });
a.push({ num: l });
for (var p = 0; p < a.length; p++) {
a[p].offsetX = e;
e = m(e, o, a[p].num, t);
if (p < a.length - 1) {
if (a[p].num != 10 && a[p + 1].num != 10) {
e += n
}
}
}
if (h.length == 0) {
h = a
} else {
for (var C = 0; C < h.length; C++) {
if (h[C].num != a[C].num) {
s(a[C]);
h[C].num = a[C].num
}
}
}
i(t);
g();
return r
}
function s(t) {
var a = t.num;
var n = u[a];
for (var e = 0; e < n.length; e++) {
for (var f = 0; f < n[e].length; f++) {
if (n[e][f] == 1) {
var h = {
offsetX: t.offsetX + r + r * 2 * f,
offsetY: 30 + r + r * 2 * e,
color: v[Math.floor(Math.random() * v.length)],
g: 1.5 + Math.random(),
vx: Math.pow(-1, Math.ceil(Math.random() * 10)) * 4 + Math.random(),
vy: -5
};
o.push(h)
}
}
}
}
function i(t) {
for (var a = 0; a < o.length; a++) {
t.beginPath();
t.fillStyle = o[a].color;
t.arc(o[a].offsetX, o[a].offsetY, r, 0, 2 * Math.PI);
t.fill()
}
}
function g() {
var n = 0;
for (var f = 0; f < o.length; f++) {
var v = o[f];
v.offsetX += v.vx;
v.offsetY += v.vy;
v.vy += v.g;
if (v.offsetY > a - r) {
v.offsetY = a - r;
v.vy = -v.vy * e
}
if (v.offsetX > r && v.offsetX < t - r) {
o[n] = o[f];
n++
}
}
for (; n < o.length; n++) {
o.pop()
}
}
function m(t, a, n, e) {
var f = u[n];
for (var o = 0; o < f.length; o++) {
for (var v = 0; v < f[o].length; v++) {
if (f[o][v] == 1) {
e.beginPath();
e.arc(t + r + r * 2 * v, a + r + r * 2 * o, r, 0, 2 * Math.PI);
e.fill()
}
}
}
e.beginPath();
t += f[0].length * r * 2;
return t
}
var c = document.getElementById("canvas");
c.width = t;
c.height = a;
f = c.getContext("2d");
var M = new Date;
setInterval(function () {
f.clearRect(0, 0, f.canvas.width, f.canvas.height);
l(f)
}, 50)
}
// 侧边栏公告提醒 - 多RSS监控版(精准到秒+无兜底)
const COOKIE_EXPIRE_YEARS = 10;
const NOTICE_DETAIL_PATH = '/notice';
const RSS_URLS = [
'https://git.anian.net/anian/halo-theme-pix/rss/branch/master',
];
async function getAllLatestNoticeDatesFromRSS() {
try {
const rssResponses = await Promise.all(
RSS_URLS.map(url => fetch(url))
);
for (let [index, response] of rssResponses.entries()) {
if (!response.ok) {
throw new Error(`RSS ${RSS_URLS[index]} 请求失败:${response.status}`);
}
}
const allPubDates = [];
for (let response of rssResponses) {
const xmlText = await response.text();
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlText, 'text/xml');
const items = xmlDoc.querySelectorAll('item');
if (items.length === 0) continue;
const itemDates = Array.from(items).map(item => {
const pubDateStr = item.querySelector('pubDate').textContent;
const pubDate = new Date(pubDateStr);
return `${pubDate.getFullYear()}-${String(pubDate.getMonth() + 1).padStart(2, '0')}-${String(pubDate.getDate()).padStart(2, '0')}-${String(pubDate.getHours()).padStart(2, '0')}-${String(pubDate.getMinutes()).padStart(2, '0')}-${String(pubDate.getSeconds()).padStart(2, '0')}`;
});
allPubDates.push(itemDates[0]);
}
const sortedDates = allPubDates.sort((a, b) => new Date(b) - new Date(a));
const combinedDateStr = sortedDates.join('_'); // 用_分隔多个日期
return combinedDateStr;
} catch (error) {
return null;
}
}
// 标记已读(接收拼接后的日期字符串)
function markAsRead(combinedDateStr) {
if (!combinedDateStr) return; // 无有效日期则不操作
const noticeBubble = document.getElementById('noticeBubble');
const noticeBtn = document.getElementById('noticeBtn');
if (!noticeBubble || !noticeBtn) return;
$.cookie('latest_notice_date', combinedDateStr, { path: '/', expires: 365 });
noticeBubble.classList.remove('show');
noticeBtn.classList.remove('has-notice');
}
// 检测公告详情页并标记已读
function checkNoticeDetailPage(combinedDateStr) {
if (!combinedDateStr) return; // 无有效日期则不检查
const currentPath = window.location.pathname.replace(/\/$/, '');
const local_notice = $.cookie('latest_notice_date');
const hasUnread = !local_notice || local_notice !== combinedDateStr;
if (currentPath === NOTICE_DETAIL_PATH && hasUnread) {
markAsRead(combinedDateStr);
}
}
// 通知按钮绑定
function bindGlobalNoticeEvents(combinedDateStr) {
if (document.body.dataset.noticeEventsBound) return;
document.addEventListener('click', (e) => {
const noticeBtn = document.getElementById('noticeBtn');
if (noticeBtn && (e.target === noticeBtn || noticeBtn.contains(e.target))) {
markAsRead(combinedDateStr);
}
});
document.body.dataset.noticeEventsBound = 'true';
}
// 异步初始化(无兜底逻辑)
async function initNoticeTip() {
// 1. 获取所有RSS的拼接日期字符串,失败则直接终止
const combinedDateStr = await getAllLatestNoticeDatesFromRSS();
if (!combinedDateStr) return; // 【核心】RSS失败则不检查、不显示提醒
const noticeBubble = document.getElementById('noticeBubble');
const noticeBtn = document.getElementById('noticeBtn');
if (!noticeBubble || !noticeBtn) return;
const local_notice = $.cookie('latest_notice_date');
const hasUnread = !local_notice || local_notice !== combinedDateStr;
// 2. 只有RSS获取成功,才判断并显示/隐藏提醒
if (hasUnread) {
noticeBubble.classList.add('show');
noticeBtn.classList.add('has-notice');
$('.footer_menu a[href="/navigator"]').css('color', '#ecc94b').find('i').css('color', '#ecc94b');
} else {
noticeBubble.classList.remove('show');
noticeBtn.classList.remove('has-notice');
}
bindGlobalNoticeEvents(combinedDateStr);
checkNoticeDetailPage(combinedDateStr);
}
// 测速侧边栏
const anianxSpeedBubble = document.getElementById("anianxBubble"),
anianxSpeedBubbleText = document.getElementById("anianxBubbleText"),
anianxSpeedGroup = document.querySelector(".anianx-group"),
anianxSpeedMainLine = document.querySelector('[data-anianx-type="main"]'),
anianxSpeedTestLine = document.querySelector('[data-anianx-type="test"]'),
anianxSpeedSubLine = document.querySelector('[data-anianx-type="sub"]');
let anianxSpeedGlobalLock = false;
function anianxSpeedMoveArrow(btn) {
if (anianxSpeedGlobalLock) return;
const btnRect = btn.getBoundingClientRect(),
groupRect = anianxSpeedGroup.getBoundingClientRect(),
center = (btnRect.left - groupRect.left) + (btnRect.width / 2);
anianxSpeedBubble.style.setProperty("--anianx-arrow", center + "px");
}
function anianxSpeedSetTooltip(btn, text) {
if (!btn) return;
btn.setAttribute("title", text);
btn.setAttribute("uk-tooltip", "pos: top; offset: 2;");
}
function anianxSpeedClearTooltip(btn) {
if (!btn) return;
btn.removeAttribute("title");
btn.removeAttribute("uk-tooltip");
}
function anianxSpeedFetchLuckWithTimeout(timeout) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeout);
return fetch("https://api.anian.net/luck/api", {
signal: controller.signal
}).then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}).finally(() => {
clearTimeout(timer);
});
}
function anianxSpeedBuildLuckTooltip(idText, poetryText, meaningText, explanationText) {
const signText = idText ? `第${idText}签。` : "第?签";
return [
signText,
poetryText || "",
meaningText || "",
explanationText || ""
].join("||  ");
}
if (anianxSpeedMainLine) {
anianxSpeedMainLine.addEventListener("click", () => {
if (anianxSpeedGlobalLock) return;
anianxSpeedMoveArrow(anianxSpeedMainLine);
anianxSpeedGlobalLock = true;
anianxSpeedClearTooltip(anianxSpeedBubbleText);
anianxSpeedBubbleText.classList.add("anianx-loading");
anianxSpeedBubbleText.innerText = "抽取中";
const request = anianxSpeedFetchLuckWithTimeout(5000);
request.then(data => {
const result = data || {};
const typeText = result.type || "";
const titleText = result.title || "";
const idText = result.id || "";
const explanationText = result.explanation || "";
const poetryText = result.poetry || "";
const meaningText = result.meaning || "";
anianxSpeedBubbleText.innerText = [typeText, titleText].filter(Boolean).join(" · ") || "失败:超时或发生错误";
anianxSpeedSetTooltip(anianxSpeedBubbleText, anianxSpeedBuildLuckTooltip(idText, poetryText, meaningText, explanationText));
}).catch(() => {
anianxSpeedClearTooltip(anianxSpeedBubbleText);
anianxSpeedBubbleText.innerText = "失败:超时或发生错误";
}).finally(() => {
anianxSpeedBubbleText.classList.remove("anianx-loading");
anianxSpeedGlobalLock = false;
});
});
}
if (anianxSpeedTestLine) {
anianxSpeedTestLine.addEventListener("click", () => {
if (anianxSpeedGlobalLock) return;
anianxSpeedMoveArrow(anianxSpeedTestLine);
anianxSpeedGlobalLock = true;
anianxSpeedClearTooltip(anianxSpeedBubbleText);
anianxSpeedBubbleText.classList.add("anianx-loading");
anianxSpeedBubbleText.innerText = "测速中";
Promise.all([
anianxSpeedTestWithTimeout(10000),
anianxSpeedFetchIpWithTimeout(5000)
]).then(([speedResult, ipResult]) => {
anianxSpeedBubbleText.classList.remove("anianx-loading");
anianxSpeedBubbleText.innerText = speedResult;
const tooltipText = anianxSpeedBuildIpTooltip(ipResult);
anianxSpeedSetTooltip(anianxSpeedBubbleText, tooltipText);
}).catch(() => {
anianxSpeedClearTooltip(anianxSpeedBubbleText);
anianxSpeedBubbleText.classList.remove("anianx-loading");
anianxSpeedBubbleText.innerText = "失败:超时或发生错误";
}).finally(() => {
anianxSpeedGlobalLock = false;
});
});
}
if (anianxSpeedSubLine) {
anianxSpeedSubLine.addEventListener("click", () => {
if (anianxSpeedGlobalLock) return;
anianxSpeedMoveArrow(anianxSpeedSubLine);
anianxSpeedGlobalLock = true;
anianxSpeedClearTooltip(anianxSpeedBubbleText);
anianxSpeedBubbleText.classList.add("anianx-loading");
anianxSpeedBubbleText.innerText = "加载中";
anianxSpeedFetchXiehouyuWithTimeout(5000).then(data => {
anianxSpeedBubbleText.classList.remove("anianx-loading");
if (data && data.riddle) {
anianxSpeedBubbleText.innerText = data.riddle;
// 设置tooltip显示答案
const tooltipText = data.answer || "失败:超时或发生错误";
anianxSpeedSetTooltip(anianxSpeedBubbleText, tooltipText);
} else {
anianxSpeedClearTooltip(anianxSpeedBubbleText);
anianxSpeedBubbleText.innerText = "失败:超时或发生错误";
}
}).catch(() => {
anianxSpeedClearTooltip(anianxSpeedBubbleText);
anianxSpeedBubbleText.classList.remove("anianx-loading");
anianxSpeedBubbleText.innerText = "失败:超时或发生错误";
}).finally(() => {
anianxSpeedGlobalLock = false;
});
});
}
function anianxSpeedTestWithTimeout(timeout) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeout);
return new Promise(async (resolve, reject) => {
try {
const t0 = Date.now();
const res = await fetch(`/upload/dy-32097365860-260719-1.mp4?t=${Date.now()}`, {
signal: controller.signal
});
const blob = await res.blob();
const size = blob.size;
const sec = (Date.now() - t0) / 1000;
const mbps = ((size * 8) / (sec * 1024 * 1024)).toFixed(2);
clearTimeout(timer);
resolve("访问速率:" + mbps + " Mbps");
} catch (e) {
clearTimeout(timer);
reject(e);
}
});
}
function anianxSpeedFetchIpWithTimeout(timeout) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeout);
return fetch("https://api.anian.net/ip/api", {
signal: controller.signal
}).then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}).then(data => {
clearTimeout(timer);
return {
ip: data.ip || "",
region: data.region || ""
};
}).catch(e => {
clearTimeout(timer);
return {
ip: "",
region: ""
};
});
}
function anianxSpeedBuildIpTooltip(ipInfo) {
if (!ipInfo || (!ipInfo.ip && !ipInfo.region)) {
return "失败:超时或发生错误";
}
const lines = [];
if (ipInfo.ip) {
lines.push(`IP地址: ${ipInfo.ip}`);
}
if (ipInfo.region) {
lines.push(`
${ipInfo.region}`);
}
return lines.join("\n");
}
function anianxSpeedFetchXiehouyuWithTimeout(timeout) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeout);
return fetch("https://api.anian.net/riddle/api", {
signal: controller.signal
}).then(response => {
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}).then(data => {
clearTimeout(timer);
return data;
}).catch(e => {
clearTimeout(timer);
return null;
});
}
function initjump() {
// 登录登出、发布更新等操作后,显示提示信息
let closeLoading = null;
const loadType = $.cookie('load_type');
if (loadType) {
$.removeCookie('load_type', { path: '/' });
switch (loadType) {
case 'create':
cocoMessage.success('发布成功!');
break;
case 'update':
cocoMessage.success('更新成功!');
break;
case 'login':
cocoMessage.success('登录成功!');
break;
case 'logout':
cocoMessage.success('登出成功!');
break;
}
}
}
// 侧边栏订阅函数
async function handleSubscribe(event) {
event.preventDefault();
const form = event.target;
const input = form.querySelector(".subscribe-input");
const btn = form.querySelector(".subscribe-btn");
const msg = document.getElementById("subscribe-message");
const email = input.value.trim();
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
return show("请输入正确格式的邮箱地址", "error");
}
btn.disabled = true;
show("正在提交...");
try {
const res = await fetch(
"/apis/api.flow.post.kunkunyu.com/v1alpha1/follows/-/submit",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email })
}
);
if (res.status === 200) {
show("订阅成功", "success");
input.value = "";
} else {
show("您已订阅过", "warning");
}
} catch {
show("网络错误,请稍后再试", "error");
}
btn.disabled = false;
function show(text, type) {
msg.textContent = text;
msg.className = `subscribe-message ${type}`;
}
}
// 图库兼容视频监听刷新排版
let wfTimer = null;
document.addEventListener('loadedmetadata', function (e) {
if (
e.target.tagName === 'VIDEO' &&
e.target.closest('.gallery-photos')
) {
clearTimeout(wfTimer);
wfTimer = setTimeout(() => {
waterfall('.gallery-photos');
}, 300);
}
}, true);
function initBlog() {
pix.initTopBar(),
pix.getMsg(),
initAgree(),
pix.initGalleryPhotos(),
pix.loadLightbox(),
pix.topCategoriesBarScroll(),
pix.topTableBarScroll(),
pix.centerCategoryNavActive(),
getMomentAudio(),
Theme.toc.all_open && autotree(),
highlightActiveMenu(),
syncFooterWithAudioState(),
highlightMenu(),
initializeMomentFold()
// nextBanner()
}
$(document).ready(function () {
pix.roleMoments();
initBlog();
initPageJumpSteppers();
initPreviousPageButton()
setPageGrayscale();
anian_renderLunarUI();
updateMusicBtnColor('default');
initGreenDigitalClock();
initNoticeTip();
initjump();
});