重构课外书;修复异常;优化体验
This commit is contained in:
+15
-462
@@ -246,446 +246,26 @@ function confirmPixarAction() {
|
||||
customLogout();
|
||||
}
|
||||
|
||||
// 豆瓣页:分类筛选 + AJAX加载(不依赖 finder API)
|
||||
function init_douban_page() {
|
||||
var $page = $('.douban_page');
|
||||
if ($page.length === 0) {
|
||||
return;
|
||||
}
|
||||
function initDoubanDetailLinks() {
|
||||
document.querySelectorAll('.douban_page:not(.douban_detail_page) .douban_card_item').forEach(function (card) {
|
||||
var link = card.querySelector('.douban_detail_link');
|
||||
var title = card.querySelector('.douban_title_text');
|
||||
var content = card.querySelector('.douban_content_main');
|
||||
|
||||
var $list = $('#douban_item');
|
||||
var $pagination = $('#douban_pagination');
|
||||
var $paginationBtn = $('#douban_pagination a');
|
||||
|
||||
if ($list.length === 0 || $paginationBtn.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var state = {
|
||||
page: 1,
|
||||
size: 10,
|
||||
type: '',
|
||||
loading: false
|
||||
};
|
||||
|
||||
function escapeHtml(input) {
|
||||
if (input === null || input === undefined) {
|
||||
return '';
|
||||
}
|
||||
return String(input)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function formatTime(isoTime) {
|
||||
if (!isoTime) {
|
||||
return '--';
|
||||
}
|
||||
var date = new Date(isoTime);
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
return '--';
|
||||
}
|
||||
var year = date.getFullYear();
|
||||
var month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
var day = String(date.getDate()).padStart(2, '0');
|
||||
return year + '-' + month + '-' + day;
|
||||
}
|
||||
|
||||
function buildRequestUrl(page, type) {
|
||||
var query = new URLSearchParams({
|
||||
page: String(page),
|
||||
size: String(state.size)
|
||||
});
|
||||
if (type) {
|
||||
query.append('type', type);
|
||||
}
|
||||
return '/apis/api.douban.moony.la/v1alpha1/doubanmovies?' + query.toString();
|
||||
}
|
||||
|
||||
function renderEmpty() {
|
||||
return '<div class="loading_box"><img src="/themes/theme-pix/assets/img/no-data.webp" alt="暂无内容" style="max-width: 280px; width: 100%; height: auto;"></div>';
|
||||
}
|
||||
|
||||
function parseScoreValue(rawScore) {
|
||||
if (rawScore === null || rawScore === undefined || rawScore === '') {
|
||||
return null;
|
||||
}
|
||||
var scoreText = String(rawScore);
|
||||
var matched = scoreText.match(/(\d+(?:\.\d+)?)/);
|
||||
if (!matched || !matched[1]) {
|
||||
return null;
|
||||
}
|
||||
var scoreNumber = parseFloat(matched[1]);
|
||||
if (Number.isNaN(scoreNumber)) {
|
||||
return null;
|
||||
}
|
||||
if (scoreNumber < 0) {
|
||||
scoreNumber = 0;
|
||||
}
|
||||
if (scoreNumber > 5) {
|
||||
scoreNumber = 5;
|
||||
}
|
||||
return scoreNumber;
|
||||
}
|
||||
|
||||
function renderTypeNav(typeList) {
|
||||
var $navList = $('.douban_cat_nav ul');
|
||||
if ($navList.length === 0) {
|
||||
if (!link || !title || !content) {
|
||||
return;
|
||||
}
|
||||
|
||||
var navHtml = ['<li><a data-type="" class="cat-link active">全部<span></span></a></li>'];
|
||||
var seen = {};
|
||||
|
||||
if (Array.isArray(typeList)) {
|
||||
typeList.forEach(function (item) {
|
||||
var key = item && item.key !== undefined && item.key !== null ? String(item.key).trim() : '';
|
||||
if (!key || seen[key]) {
|
||||
return;
|
||||
}
|
||||
seen[key] = true;
|
||||
var safeKey = escapeHtml(key);
|
||||
navHtml.push('<li><a data-type="' + safeKey + '" class="cat-link">' + safeKey + '<span></span></a></li>');
|
||||
});
|
||||
}
|
||||
|
||||
$navList.html(navHtml.join(''));
|
||||
}
|
||||
|
||||
function renderScore(rawScore) {
|
||||
var scoreValue = parseScoreValue(rawScore);
|
||||
if (scoreValue === null) {
|
||||
return '暂无评分';
|
||||
}
|
||||
var formatted = scoreValue.toFixed(1);
|
||||
return formatted + ' / 5.0';
|
||||
}
|
||||
|
||||
function renderItem(item) {
|
||||
var spec = item && item.spec ? item.spec : {};
|
||||
var faves = item && item.faves ? item.faves : {};
|
||||
var name = escapeHtml(spec.name || '未命名条目');
|
||||
var link = escapeHtml(spec.link || 'javascript:void(0);');
|
||||
var poster = escapeHtml(spec.poster || '/themes/theme-pix/assets/img/theme/banner-all.webp');
|
||||
var rawScore = faves.score || spec.score || '';
|
||||
var createTime = escapeHtml(formatTime(faves.createTime));
|
||||
var dataType = escapeHtml(spec.type || '--');
|
||||
var contentText = escapeHtml(spec.cardSubtitle || '暂无内容简介');
|
||||
var pid = escapeHtml((item.metadata && item.metadata.name) || ('douban-' + Date.now()));
|
||||
var scoreText = renderScore(rawScore);
|
||||
|
||||
return '' +
|
||||
'<div id="post-' + pid + '" class="loop_content p_item moment_item douban_card_item uk-animation-slide-bottom-small">' +
|
||||
' <div class="p_item_inner douban_card_inner">' +
|
||||
' <div class="douban_text_col">' +
|
||||
' <div class="douban_title_row">' +
|
||||
' <a class="douban_title_text" target="_blank" rel="noopener" href="' + link + '">' +
|
||||
' ' + name +
|
||||
' </a>' +
|
||||
' </div>' +
|
||||
' <div class="douban_media_col">' +
|
||||
' <img class="douban_poster_img" src="' + poster + '" alt="' + name + '">' +
|
||||
' </div>' +
|
||||
' <div class="douban_sub_meta">' +
|
||||
' <time class="douban_time_text" datetime="' + createTime + '">' + createTime + '</time>' +
|
||||
' <span class="douban_type_badge">' + dataType + '</span>' +
|
||||
' <span class="douban_score_badge">' + escapeHtml(scoreText) + '</span>' +
|
||||
' </div>' +
|
||||
' <div class="douban_content_box">' +
|
||||
' <p class="douban_content_main douban_content_collapsed" data-full="' + escapeHtml(contentText) + '">' + contentText + '</p>' +
|
||||
' <a class="douban_expand_btn" style="display:none;">展开</a>' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
' </div>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
function updatePagination(hasNext, nextPage) {
|
||||
if (hasNext) {
|
||||
$paginationBtn
|
||||
.attr('data-next-page', String(nextPage))
|
||||
.attr('data', String(nextPage))
|
||||
.text((window.Theme && Theme.site_page) ? Theme.site_page : '翻阅更多')
|
||||
.show();
|
||||
$pagination.removeClass('u-hide').css('display', 'flex');
|
||||
} else {
|
||||
$paginationBtn.removeAttr('data-next-page').removeAttr('data');
|
||||
$paginationBtn.hide();
|
||||
$pagination.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function renderList(data, isAppend) {
|
||||
var items = (data && data.items) ? data.items : [];
|
||||
if (!isAppend) {
|
||||
$list.empty();
|
||||
}
|
||||
if (items.length === 0 && !isAppend) {
|
||||
$list.html(renderEmpty());
|
||||
updatePagination(false, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
var html = items.map(renderItem).join('');
|
||||
$list.append($(html).fadeIn(300));
|
||||
if (typeof lazyLoadInstance !== 'undefined') {
|
||||
lazyLoadInstance.update();
|
||||
}
|
||||
if (typeof initializeMomentFold === 'function') {
|
||||
initializeMomentFold();
|
||||
}
|
||||
initializeDoubanExpand();
|
||||
updatePagination(!!data.hasNext, (data.page || state.page) + 1);
|
||||
}
|
||||
|
||||
function initializeDoubanExpand() {
|
||||
var collapsedHeight = 89.6;
|
||||
$(document).off('click.doubanExpand', '.douban_expand_btn').on('click.doubanExpand', '.douban_expand_btn', function (e) {
|
||||
e.preventDefault();
|
||||
var $btn = $(this);
|
||||
var $content = $btn.prev('.douban_content_main');
|
||||
if ($content.length === 0) {
|
||||
return;
|
||||
}
|
||||
if ($content.hasClass('is-expanded')) {
|
||||
$content.removeClass('is-expanded');
|
||||
$content.css('max-height', collapsedHeight + 'px');
|
||||
$btn.text('展开');
|
||||
} else {
|
||||
var contentEl = $content[0];
|
||||
var fullHeight = $content.data('fullHeight') || (contentEl ? contentEl.scrollHeight : 0);
|
||||
$content.addClass('is-expanded');
|
||||
$content.css('max-height', fullHeight + 'px');
|
||||
$btn.text('收起');
|
||||
}
|
||||
});
|
||||
|
||||
$('.douban_content_main').each(function () {
|
||||
var $content = $(this);
|
||||
var $btn = $content.next('.douban_expand_btn');
|
||||
if ($btn.length === 0) {
|
||||
return;
|
||||
}
|
||||
var scrollHeight = this.scrollHeight;
|
||||
var clientHeight = this.clientHeight;
|
||||
if (scrollHeight > clientHeight) {
|
||||
$btn.show();
|
||||
$content.data('fullHeight', scrollHeight);
|
||||
$content.css('max-height', collapsedHeight + 'px');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function requestList(page, type, isAppend, hooks) {
|
||||
hooks = hooks || {};
|
||||
if (state.loading) {
|
||||
return;
|
||||
}
|
||||
state.loading = true;
|
||||
var appendStartIndex = isAppend ? $list.children('.p_item').length : 0;
|
||||
var oldState = {
|
||||
listHtml: $list.html(),
|
||||
paginationVisible: $pagination.is(':visible'),
|
||||
btnVisible: $paginationBtn.is(':visible'),
|
||||
btnText: $paginationBtn.text(),
|
||||
btnNextPage: $paginationBtn.attr('data-next-page')
|
||||
};
|
||||
var apiUrl = buildRequestUrl(page, type);
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: apiUrl,
|
||||
dataType: 'json',
|
||||
beforeSend: function () {
|
||||
if (!isAppend) {
|
||||
$list.html('<div class="loading_box"><div uk-spinner></div></div>');
|
||||
$pagination.hide();
|
||||
} else {
|
||||
$paginationBtn.hide();
|
||||
if ($('#douban_pagination .douban-more-loading').length === 0) {
|
||||
$('#douban_pagination .post-paging').append('<div class="douban-more-loading"><div uk-spinner></div></div>');
|
||||
}
|
||||
$pagination.css('display', 'flex');
|
||||
}
|
||||
},
|
||||
success: function (data) {
|
||||
state.page = page;
|
||||
renderList(data || {}, !!isAppend);
|
||||
if (typeof hooks.onSuccess === 'function') {
|
||||
hooks.onSuccess(data || {});
|
||||
}
|
||||
if (isAppend) {
|
||||
var $newItems = $list.children('.p_item').slice(appendStartIndex);
|
||||
if ($newItems.length > 0) {
|
||||
var $scrollBody = (typeof $body !== 'undefined') ? $body : $('html,body');
|
||||
var targetTop = $newItems.first().offset().top - 58;
|
||||
if (!window.scroll_param || (!window.loadMoreTimeout && window.scroll_param > targetTop)) {
|
||||
$scrollBody.animate({ scrollTop: targetTop }, 500);
|
||||
} else {
|
||||
window.forceStopLoading = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
cocoMessage.error('数据获取失败');
|
||||
if (!isAppend) {
|
||||
if ($.trim(oldState.listHtml || '') !== '') {
|
||||
$list.html(oldState.listHtml);
|
||||
} else {
|
||||
$list.html(renderEmpty());
|
||||
}
|
||||
}
|
||||
if (oldState.paginationVisible) {
|
||||
$pagination.css('display', 'flex');
|
||||
} else {
|
||||
$pagination.hide();
|
||||
}
|
||||
if (oldState.btnVisible) {
|
||||
$paginationBtn.show();
|
||||
} else {
|
||||
$paginationBtn.hide();
|
||||
}
|
||||
if (oldState.btnText) {
|
||||
$paginationBtn.text(oldState.btnText);
|
||||
}
|
||||
if (oldState.btnNextPage) {
|
||||
$paginationBtn.attr('data-next-page', oldState.btnNextPage);
|
||||
$paginationBtn.attr('data', oldState.btnNextPage);
|
||||
}
|
||||
if (typeof hooks.onError === 'function') {
|
||||
hooks.onError();
|
||||
}
|
||||
},
|
||||
complete: function () {
|
||||
state.loading = false;
|
||||
$('#douban_pagination .douban-more-loading').remove();
|
||||
$('.douban_cat_nav .cat-link').removeClass('disabled');
|
||||
$paginationBtn.text((window.Theme && Theme.site_page) ? Theme.site_page : '翻阅更多');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).off('click.doubanCat', '.douban_cat_nav .cat-link').on('click.doubanCat', '.douban_cat_nav .cat-link', function () {
|
||||
var $this = $(this);
|
||||
if ($this.hasClass('disabled')) {
|
||||
return false;
|
||||
}
|
||||
if ($this.hasClass('active')) {
|
||||
if (window._tagSwitchCallback) {
|
||||
window._tagSwitchCallback.resolve();
|
||||
window._tagSwitchCallback = null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$('.douban_cat_nav .cat-link').addClass('disabled');
|
||||
|
||||
var $activeBefore = $('.douban_cat_nav .cat-link.active');
|
||||
var oldType = state.type;
|
||||
var targetType = $this.attr('data-type') || '';
|
||||
var targetTag = $this.clone().find('span').remove().end().text().trim();
|
||||
|
||||
state.page = 1;
|
||||
state.type = targetType;
|
||||
|
||||
requestList(1, state.type, false, {
|
||||
onSuccess: function () {
|
||||
$this.addClass('active').parent().siblings().children('.cat-link').removeClass('active');
|
||||
if (window.pix && typeof pix.centerCategoryNavActive === 'function') {
|
||||
pix.centerCategoryNavActive($this);
|
||||
}
|
||||
|
||||
var currentUrl = new URL(window.location.href);
|
||||
if (!targetTag || targetTag === '全部') {
|
||||
currentUrl.searchParams.delete('tag');
|
||||
} else {
|
||||
currentUrl.searchParams.set('tag', targetTag);
|
||||
}
|
||||
history.pushState({ url: currentUrl.pathname + currentUrl.search }, '', currentUrl.pathname + currentUrl.search);
|
||||
|
||||
// 分类切换后重置分页记录,避免自动恢复加载旧分类页数
|
||||
$.removeCookie('page', { path: '/' });
|
||||
|
||||
if (window._tagSwitchCallback) {
|
||||
window._tagSwitchCallback.resolve();
|
||||
window._tagSwitchCallback = null;
|
||||
}
|
||||
},
|
||||
onError: function () {
|
||||
state.type = oldType;
|
||||
if ($activeBefore.length > 0) {
|
||||
$activeBefore.addClass('active').parent().siblings().children('.cat-link').removeClass('active');
|
||||
}
|
||||
if (window._tagSwitchCallback) {
|
||||
window._tagSwitchCallback.reject();
|
||||
window._tagSwitchCallback = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).off('click.doubanMore', '#douban_pagination a').on('click.doubanMore', '#douban_pagination a', function () {
|
||||
if (state.loading) {
|
||||
return false;
|
||||
}
|
||||
var pageAttr = $(this).attr('data-next-page') || $(this).attr('data');
|
||||
var nextPage = parseInt(pageAttr, 10);
|
||||
if (!nextPage || Number.isNaN(nextPage)) {
|
||||
return false;
|
||||
}
|
||||
requestList(nextPage, state.type, true, {
|
||||
onSuccess: function () {
|
||||
// 与 app.js 现有逻辑保持一致:记录当前已加载到的页码
|
||||
$.cookie('page', nextPage, { path: '/' });
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
function applyUrlTagState() {
|
||||
var urlTag = new URLSearchParams(window.location.search).get('tag');
|
||||
if (urlTag && urlTag.trim() !== '') {
|
||||
var $matchedTag = $('.douban_cat_nav .cat-link').filter(function () {
|
||||
var tagText = $(this).clone().find('span').remove().end().text().trim();
|
||||
return tagText === urlTag;
|
||||
}).first();
|
||||
if ($matchedTag.length > 0) {
|
||||
$matchedTag.addClass('active').parent().siblings().children('.cat-link').removeClass('active');
|
||||
if (window.pix && typeof pix.centerCategoryNavActive === 'function') {
|
||||
pix.centerCategoryNavActive($matchedTag);
|
||||
}
|
||||
state.type = $matchedTag.attr('data-type') || '';
|
||||
} else {
|
||||
state.type = $('.douban_cat_nav .cat-link.active').attr('data-type') || '';
|
||||
}
|
||||
} else {
|
||||
state.type = $('.douban_cat_nav .cat-link.active').attr('data-type') || '';
|
||||
if (window.pix && typeof pix.centerCategoryNavActive === 'function') {
|
||||
pix.centerCategoryNavActive($('.douban_cat_nav .cat-link.active').first());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '/apis/api.douban.moony.la/v1alpha1/doubanmovies/-/types',
|
||||
dataType: 'json',
|
||||
success: function (data) {
|
||||
var typeList = Array.isArray(data) ? data : ((data && Array.isArray(data.items)) ? data.items : []);
|
||||
renderTypeNav(typeList);
|
||||
},
|
||||
complete: function () {
|
||||
applyUrlTagState();
|
||||
requestList(1, state.type, false);
|
||||
}
|
||||
var titleOverflow = title.scrollWidth > title.clientWidth;
|
||||
var contentOverflow = content.scrollHeight > content.clientHeight + 1;
|
||||
link.classList.toggle('is-visible', titleOverflow || contentOverflow);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('pjax:complete', initDoubanDetailLinks);
|
||||
document.addEventListener('DOMContentLoaded', initDoubanDetailLinks);
|
||||
window.addEventListener('resize', initDoubanDetailLinks);
|
||||
|
||||
// 打开确认模态框
|
||||
function openModal(title, msg, type) {
|
||||
var modal = $('#momentsDeleteModal');
|
||||
@@ -699,32 +279,5 @@ function openModal(title, msg, type) {
|
||||
modal.fadeIn(200);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// = = = = = = = = = = = = = = = = 触发器 = = = = = = = = = = = = = = = =
|
||||
|
||||
// 集合:PJAX(初始化执行+PJAX执行)
|
||||
function init_anian_pjax() {
|
||||
// modify_moment_video_size();
|
||||
init_douban_page();
|
||||
}
|
||||
|
||||
// 集合:初始化(仅初始化执行一次)
|
||||
function init_anian_inport() {
|
||||
init_anian_pjax();
|
||||
modify_m_bottom_music_button_link();
|
||||
}
|
||||
|
||||
// PJAX监听
|
||||
document.addEventListener('pjax:complete', function () {
|
||||
init_anian_pjax();
|
||||
})
|
||||
|
||||
// 入口
|
||||
init_anian_inport();
|
||||
// 主题通用交互初始化
|
||||
modify_m_bottom_music_button_link();
|
||||
|
||||
Reference in New Issue
Block a user