fix: 管理员编辑跳过邮箱校验 + 返回顶部 rAF 丝滑滚动 + admin.js 正则笔误 + 页面标题污染

- artalk.js: beforeSubmit 在编辑态跳过昵称/邮箱校验(管理员改评论不再被拦)
- floating-tools.js: 返回顶部/去评论改 rAF + easeInOutCubic 自绘,原生 smooth 不可靠
- admin.js: 修 5 处 //s //n 正则笔误(整脚本 SyntaxError 致后台全灰),需 wrangler deploy
- artalk.html: 显式传 pageTitle(不再读 document.title,PJAX 竞态致文章页标题被记成「留言」)
- artalk.js: conf 缓存合并前剔除 pageKey/pageTitle/pageThumb,杜绝跨页串值
This commit is contained in:
zqlit committed 2026-10-04 18:30:30 +08:00
1 parent e8c991274a
commit 437cd339ad
4 files changed
+59 -10

No files matched your search

+21 -3
View File
@@ -771,7 +771,19 @@ window.initArtalk = function() {
// Try to read cache
try {
var raw = localStorage.getItem(confKey);
if (raw) cachedConf = JSON.parse(raw);
if (raw) {
cachedConf = JSON.parse(raw);
// 剔除页面级字段:缓存来自「上一个页面」的实例 conf,若把它的
// pageKey/pageTitle 合并进当前页就会串页 —— 历史上文章页在后台
// 标题被污染成「留言」(用户从留言页 PJAX 进文章页)就是这个原因。
// pageKey / pageTitle 现已全部由 window.artalkConfig 显式提供,
// 这里删掉属于双保险,防止 config 哪天漏传又被旧值钻空子。
if (cachedConf && typeof cachedConf === 'object') {
['pageKey', 'pageTitle', 'pageThumb'].forEach(function(k) {
delete cachedConf[k];
});
}
}
} catch(e) {
console.warn('Failed to parse Artalk cache:', e);
}
@@ -1596,9 +1608,15 @@ artalk.on('list-loaded', function() {
editor = ed || editor;
var content = '';
try { content = String(ed.getContentFinal() || '').trim(); } catch (e) {}
var els = headerEls();
if (!content) { toast('warning', '评论内容不能为空'); return; }
// 编辑已有评论(管理员)用登录身份提交,没有昵称/邮箱输入框,
// 硬校验会把管理员挡在「编辑」外面 —— 直接放行,内容校验已在上面做过
var st = '';
try { st = (ed && typeof ed.getState === 'function' && ed.getState()) || ''; } catch (e) {}
if (st === 'edit') { next(); return; }
var els = headerEls();
var nick = val(els.nick), email = val(els.email);
if (!nick) { toast('warning', '请先填写昵称'); focusEl(els.nick); return; }
if (!email) { toast('warning', '请先填写邮箱(有人回复你时才能通知到)'); focusEl(els.email); return; }
@@ -1,3 +1,29 @@
// 自绘平滑滚动:浏览器原生 behavior:'smooth' 又快又硬(约 300ms 且不可调),
// 还会被系统的「减少动态效果」降级成瞬移。用 rAF + easeInOutCubic 自绘,
// 时长随距离自适应,滚动一旦被用户滚轮/触摸打断立即让位。
window.smoothScrollTo = function(targetY, duration) {
var startY = window.scrollY;
var diff = targetY - startY;
if (Math.abs(diff) < 2) return;
// 短距离快、长距离慢一些,但都 clamp 在 420~950ms,保证观感一致
var dur = duration || Math.min(950, Math.max(420, Math.abs(diff) * 0.38));
if (window.__smoothScrollRAF) cancelAnimationFrame(window.__smoothScrollRAF);
var t0 = null, canceled = false;
var cancel = function() { canceled = true; };
window.addEventListener('wheel', cancel, { once: true, passive: true });
window.addEventListener('touchstart', cancel, { once: true, passive: true });
var ease = function(t) { return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; };
var step = function(ts) {
if (canceled) return;
if (t0 === null) t0 = ts;
var p = Math.min(1, (ts - t0) / dur);
window.scrollTo(0, startY + diff * ease(p));
if (p < 1) window.__smoothScrollRAF = requestAnimationFrame(step);
else window.__smoothScrollRAF = null;
};
window.__smoothScrollRAF = requestAnimationFrame(step);
};
window.refreshFloatingTools = function() {
if (typeof window.initFloatingTools !== 'function') return;
var delays = [0, 60, 180];
@@ -105,7 +131,7 @@ window.initFloatingTools = function() {
backToTopButton.addEventListener('click', function(e) {
e.preventDefault();
window.scrollTo({ top: 0, behavior: 'smooth' });
window.smoothScrollTo(0);
});
}
@@ -206,7 +232,7 @@ window.initFloatingTools = function() {
var comments = document.getElementById('Comments') || document.querySelector('.artalk');
if (comments) {
var y = comments.getBoundingClientRect().top + window.scrollY - 20;
window.scrollTo({ top: y, behavior: 'smooth' });
window.smoothScrollTo(y);
}
});
}
+5
View File
@@ -253,6 +253,11 @@
server: '{{ .Site.Params.artalk.server }}',
site: '{{ .Site.Params.artalk.site }}',
pageKey: '{{ .RelPermalink }}',
{{/* pageTitle 必须显式传:Artalk 不传时会读 document.title,而 PJAX 切页
早期脚本执行时 document.title 还是上一个页面的(经典竞态),历史上
数据库里一堆文章页的标题被污染成「留言」就是这么来的。head.html 的
<title> 就是纯 .Title,这里与它保持一致。jsonify 防标题里有引号炸模板。 */}}
pageTitle: {{ .Title | jsonify }},
emoticons: '{{ .Site.Params.artalk.emoticons | absURL }}',
aiComment: null
};