Files
kate522 5fd7c212ed fix(runtime): 按参考主题硬切换为 loader/main/auto_fun 单一 DOM 生命周期
- 删除 AksrtFrontend registry/rehydrate 双路架构及 build/public.js 拼包入口,
  前台唯一初始路径为 PHP 本地栈(jQuery 1.9.1 → Bootstrap 3.4.1)
  → loader_js(_win/aksrtData 唯一注入)→ tbquire(['main']) → runtime/main.min.js
- window.auto_fun = debounce(z_auto_fun, 100) 为唯一重扫入口;所有模块改为
  执行一次 + off/on('auto_fun.aksrt-*') 命名空间重扫,data/class 标记幂等
- 局部更新协议统一:HTML 注入 → post_ajax.ed → auto_fun();
  远程 modal → loaded.bs.modal → auto_fun();JSON 成功 → zib_ajax.success
- 灯箱恢复 Miniimgbox/imgbox 唯一 owner(imgbox-container、a[data-imgbox]、
  imgbox_data),删除 AksrtLightbox/data-aksrt-lightbox 第二实现及 CSS/overlay,
  _win.imgbox* 重新接上 post-display 设置
- 死代码清理:runtime 下 11 组被自有实现替代的旧模块副本、无消费 vendored 库、
  顶层 grade.min.js、revenue.js、无调用方的 aksrt_get_win_runtime_config(),
  以及 loader 中 16 条死 mapping
- PHP 入队改为本地栈 + loader_js,routed/widget/submit 依赖统一换绑;
  用户卡片发布按钮恢复 nav_user_newposts_btn 设置门控
- 测试对齐:新增 frontend-lifecycle-contract,重写 navigation/lazyload/toast/
  auth-source/comment/page-display/post-visual 等断言为目标架构契约

验证:node --test widget-system+navigation 223 通过 0 失败;
构建脚本重建 main/imgbox min 与 CSS bundles;改动 PHP php -l、JS node --check
全部通过;git diff --check 干净;credits 重入 harness 通过。
2026-09-03 12:44:31 +08:00

256 lines
6.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* AKSRT Yiyan — 一言轮播组件
*
* Fetches random quotes from hitokoto.cn API and auto-rotates.
* Public v1 returns one sentence per request; multi-quote carousels
* issue parallel fetches. Category `c` must be a letter a–l (or omitted).
*
* @package AKSRT
*/
(function () {
'use strict';
var API_BASE = 'https://v1.hitokoto.cn/';
var TYPE_RE = /^[a-l]$/i;
var MIN_COUNT = 1;
var MAX_COUNT = 10;
var DEFAULT_COUNT = 5;
var DEFAULT_INTERVAL_SEC = 5;
function normalizeType(raw) {
if (raw == null || raw === '') {
return '';
}
var t = String(raw).trim().toLowerCase();
return TYPE_RE.test(t) ? t : '';
}
function normalizeCount(raw) {
var n = parseInt(raw, 10);
if (isNaN(n) || n < MIN_COUNT) {
return DEFAULT_COUNT;
}
return Math.min(MAX_COUNT, n);
}
function normalizeIntervalMs(raw) {
var sec = parseInt(raw, 10);
if (isNaN(sec) || sec < 3) {
sec = DEFAULT_INTERVAL_SEC;
}
return Math.min(60, sec) * 1000;
}
function buildApiUrl(type) {
var params = new URLSearchParams();
params.set('encode', 'json');
if (type) {
params.set('c', type);
}
return API_BASE + '?' + params.toString();
}
function mapQuote(data) {
if (!data || typeof data !== 'object') {
return null;
}
var text = data.hitokoto || data.text || '';
if (!text) {
return null;
}
return {
text: String(text),
from: data.from ? String(data.from) : '',
};
}
function ensureStructure(el) {
var textEl = el.querySelector('.aksrt-yiyan__text');
if (textEl) {
return {
textEl: textEl,
fromEl: el.querySelector('.aksrt-yiyan__from'),
dotsEl: el.querySelector('.aksrt-yiyan__dots'),
};
}
var content = document.createElement('div');
content.className = 'aksrt-yiyan__content';
textEl = document.createElement('p');
textEl.className = 'aksrt-yiyan__text';
textEl.textContent = '加载中…';
content.appendChild(textEl);
var fromEl = document.createElement('p');
fromEl.className = 'aksrt-yiyan__from';
content.appendChild(fromEl);
el.appendChild(content);
var dotsEl = document.createElement('div');
dotsEl.className = 'aksrt-yiyan__dots';
dotsEl.setAttribute('aria-hidden', 'true');
el.appendChild(dotsEl);
return { textEl: textEl, fromEl: fromEl, dotsEl: dotsEl };
}
function fetchOneQuote(type) {
return fetch(buildApiUrl(type), {
credentials: 'omit',
mode: 'cors',
}).then(function (r) {
return r
.json()
.catch(function () {
return null;
})
.then(function (data) {
if (!r.ok) {
var msg =
data && data.message
? String(data.message)
: 'HTTP ' + r.status;
throw new Error(msg);
}
var quote = mapQuote(data);
if (!quote) {
throw new Error('empty');
}
return quote;
});
});
}
function fetchQuotes(type, count) {
var jobs = [];
var i;
for (i = 0; i < count; i += 1) {
jobs.push(
fetchOneQuote(type).catch(function () {
return null;
})
);
}
return Promise.all(jobs).then(function (results) {
var quotes = [];
var seen = Object.create(null);
results.forEach(function (q) {
if (!q || !q.text) {
return;
}
// Dedupe identical text from parallel random draws.
if (seen[q.text]) {
return;
}
seen[q.text] = 1;
quotes.push(q);
});
return quotes;
});
}
function initYiyan(el) {
if (el.dataset.yiyanBound) {
return;
}
el.dataset.yiyanBound = '1';
var count = normalizeCount(el.dataset.count);
var interval = normalizeIntervalMs(el.dataset.interval);
var type = normalizeType(el.dataset.type);
var parts = ensureStructure(el);
var textEl = parts.textEl;
var fromEl = parts.fromEl;
var dotsEl = parts.dotsEl;
var quotes = [];
var currentIndex = 0;
var timer = null;
function showQuote(index) {
if (!quotes.length || !textEl) {
return;
}
var q = quotes[index % quotes.length];
textEl.style.opacity = '0';
setTimeout(function () {
textEl.textContent = '"' + q.text + '"';
textEl.style.opacity = '1';
if (fromEl) {
fromEl.textContent = q.from ? '—— ' + q.from : '';
}
}, 200);
if (dotsEl) {
dotsEl.querySelectorAll('.aksrt-yiyan__dot').forEach(function (dot, i) {
dot.classList.toggle('is-active', i === index % quotes.length);
});
}
}
function nextQuote() {
if (quotes.length < 2) {
return;
}
currentIndex = (currentIndex + 1) % quotes.length;
showQuote(currentIndex);
}
function startTimer() {
if (timer) {
clearInterval(timer);
timer = null;
}
if (quotes.length > 1) {
timer = setInterval(nextQuote, interval);
}
}
function buildDots() {
if (!dotsEl || quotes.length < 2) {
if (dotsEl) {
dotsEl.innerHTML = '';
}
return;
}
dotsEl.innerHTML = '';
quotes.forEach(function (_, i) {
var dot = document.createElement('span');
dot.className = 'aksrt-yiyan__dot' + (i === 0 ? ' is-active' : '');
dotsEl.appendChild(dot);
});
}
el.addEventListener('mouseenter', function () {
if (timer) {
clearInterval(timer);
timer = null;
}
});
el.addEventListener('mouseleave', function () {
startTimer();
});
fetchQuotes(type, count)
.then(function (list) {
quotes = list;
if (!quotes.length) {
textEl.textContent = '暂无内容';
return;
}
buildDots();
showQuote(0);
startTimer();
})
.catch(function () {
textEl.textContent = '加载失败,请稍后再试';
});
}
jQuery(document).off('auto_fun.aksrt-yiyan').on('auto_fun.aksrt-yiyan', function () {
document.querySelectorAll('[data-aksrt-yiyan]').forEach(initYiyan);
});
})();