Files
mama-box/js/wh-cm.js

101 lines
7.4 KiB
JavaScript
Raw 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.
/* 星空页 · 妈妈们的留言(2026-11-07 用户:广场点「孕妈悄悄话」直接进星空页,留言自带在「说一句悄悄话」下面,
样式跟星空搭,不要白底)。
· 版式:#wcm 盖满星空页、自己滚动;上面一段透明垫高,下面是留言面板,
把原来的 .whp-bar(说一句悄悄话)挪进面板顶上,往上滑留言就盖上来。
· 数据:广场置顶笔记 wh-<话题 from> 的评论 = cm.json 模拟(AGENTS.md 12c,不得挂星)+ /plaza/comments 已审核通过的真实评论
+ 我自己发的(含审核中)。进星空页才拉 cm.json(600K+,gzip 后小很多;版本号跟广场 index.html 引的一致,共用缓存)。
· 赞只记本机 mmbox.whcm.v1(服务端计数是悄悄话第 2 步)。 */
(function () {
var page = document.getElementById('whPage'), bar = page && page.querySelector('.whp-bar');
if (!page || !bar || !window.MB_WH_THEME) return;
var TH = MB_WH_THEME(), PID = 'wh-' + TH.from.replace(/-/g, '');
var esc = function (s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]; }); };
var m = ((location.hash || '') + '&').match(/[#&]openid=([^&]*)/), OID = m ? decodeURIComponent(m[1]) : '';
var box = document.createElement('div');
box.className = 'wcm'; box.id = 'wcm';
box.innerHTML = '<div class="wcm-sp" aria-hidden="true"></div><div class="wcm-in"><div class="wcm-hd"><b>妈妈们的留言</b><span id="wcmN"></span><i class="wcm-up">上滑看看</i></div>' +
'<div class="wcm-ls" id="wcmLs"><p class="wcm-e">留言加载中…</p></div><button type="button" class="wcm-more" id="wcmMore" hidden>再看看</button></div>';
box.querySelector('.wcm-in').insertBefore(bar, box.querySelector('.wcm-hd'));
page.appendChild(box);
var ls = box.querySelector('#wcmLs'), more = box.querySelector('#wcmMore');
var LK = 'mmbox.whcm.v1', LIKE = {};
try { LIKE = JSON.parse(localStorage.getItem(LK) || '{}') || {}; } catch (e) {}
var avP = function (a) { return typeof a === 'number' ? 'guangchang/av/' + ('000' + a).slice(-4) + '.webp' : a.indexOf('av:') === 0 ? 'guangchang/av/' + a.slice(3) + '.webp' : a.charAt(0) === '/' ? a : 'assets/img/mom/' + a + '.jpg'; };
var fmt = function (n) { return n >= 10000 ? (n / 10000).toFixed(1) + 'w' : String(n); };
var ago = function (ts) {
var d = (Date.now() - ts) / 1000;
if (d < 3600) return Math.max(1, Math.round(d / 60)) + ' 分钟前';
if (d < 86400) return Math.round(d / 3600) + ' 小时前';
var t = new Date(ts + 8 * 3600e3); return (t.getUTCMonth() + 1) + '-' + t.getUTCDate();
};
var SIM = null, REAL = null, ALL = [], shown = 0, loading = false;
function load() {
if (loading || SIM) return; loading = true;
fetch('guangchang/cm.json?v=26110612').then(function (r) { return r.json(); }).then(function (j) {
var P = j.p;
SIM = (j.c[PID] || []).map(function (c, k) {
var p = P[c[0]];
return { key: 's' + k, n: p[0], av: avP(p[1]), s: p[2], t: c[1], likes: c[2],
r: c[3].map(function (x) { var q = x[0] < 0 ? null : P[x[0]]; return { n: q ? q[0] : '孕妈悄悄话', t: x[1] }; }) };
});
build();
}).catch(function () { SIM = []; build(); });
fetch('/api/mp/public/mama-box/plaza/comments?kind=post&target=' + encodeURIComponent(PID) + (OID ? '&openid=' + encodeURIComponent(OID) : ''))
.then(function (r) { return r.json(); }).then(function (j) {
var R = j && j.code === 200 && j.result || {}, top = function (c) { return !c.parent; };
REAL = (R.list || []).filter(top).map(function (c) { return { key: 'r' + c.id, n: c.nickname || '孕妈', av: c.avatar || 'assets/img/mom/k01.jpg', s: c.stage, t: c.text, likes: 0, ts: c.at, r: [] }; })
.concat((R.mine || []).filter(function (c) { return top(c) && c.status !== 'rejected'; }).map(function (c) {
return { key: 'r' + c.id, n: '我', me: 1, av: c.avatar || 'assets/img/mom/k01.jpg', s: c.stage, t: c.text, likes: 0, ts: c.at, st: c.status, r: [] }; }))
.sort(function (a, b) { return b.ts - a.ts; });
build();
}).catch(function () { REAL = []; build(); });
}
function build() {
if (!SIM || !REAL) return;
ALL = REAL.concat(SIM); shown = 0; ls.innerHTML = '';
document.getElementById('wcmN').textContent = ALL.length ? ALL.length + ' 条' : '';
if (!ALL.length) { ls.innerHTML = '<p class="wcm-e">还没有留言</p>'; more.hidden = true; return; }
add(20);
}
function item(c) {
var on = !!LIKE[c.key];
return '<div class="wcm-it"><img class="wcm-av" src="' + esc(c.av) + '" alt="" loading="lazy" onerror="this.style.visibility=\'hidden\'">' +
'<div class="wcm-bd"><p class="wcm-nm"><b>' + esc(c.n) + '</b>' + (c.s ? '<span>' + esc(c.s) + '</span>' : '') + (c.ts ? '<span>' + ago(c.ts) + '</span>' : '') + '</p>' +
'<p class="wcm-tx">' + esc(c.t) + '</p>' + (c.st === 'pending' ? '<p class="wcm-st">审核中 · 通过后大家才能看到</p>' : '') +
(c.r.length ? '<div class="wcm-rp">' + c.r.map(function (x) { return '<p><b>' + esc(x.n) + '</b>:' + esc(x.t) + '</p>'; }).join('') + '</div>' : '') + '</div>' +
'<button type="button" class="wcm-lk' + (on ? ' on' : '') + '" data-wcl="' + esc(c.key) + '" aria-label="赞"><svg viewBox="0 0 24 24"><path d="M12 20.5s-7.5-4.6-7.5-10.2A4.3 4.3 0 0112 7.6a4.3 4.3 0 017.5 2.7c0 5.6-7.5 10.2-7.5 10.2z"/></svg><span>' + fmt(c.likes + (on ? 1 : 0)) + '</span></button></div>';
}
function add(k) {
ls.insertAdjacentHTML('beforeend', ALL.slice(shown, shown + k).map(item).join(''));
shown = Math.min(ALL.length, shown + k); more.hidden = shown >= ALL.length;
}
more.addEventListener('click', function () { add(30); });
ls.addEventListener('click', function (e) {
var b = e.target.closest('[data-wcl]'); if (!b) return;
var k = b.dataset.wcl, c = ALL.filter(function (x) { return x.key === k; })[0]; if (!c) return;
if (LIKE[k]) delete LIKE[k]; else LIKE[k] = 1;
try { localStorage.setItem(LK, JSON.stringify(LIKE)); } catch (e2) {}
var on = !!LIKE[k]; b.classList.toggle('on', on); b.querySelector('span').textContent = fmt(c.likes + (on ? 1 : 0));
if (on && navigator.vibrate) navigator.vibrate(8);
});
/* 11-07 用户:页面滑不动 —— 原来垫高层 pointer-events:none,手机上按在星空上滑,滚动不归 #wcm。
现在整层都接触摸(按哪都能滑),点在垫高层上就把点击转给底下的星星 / 顶栏按钮 / 内容卡 */
var sp = box.querySelector('.wcm-sp');
sp.addEventListener('click', function (e) {
box.style.pointerEvents = 'none';
var el = document.elementFromPoint(e.clientX, e.clientY);
box.style.pointerEvents = '';
if (el && el !== sp && page.contains(el)) el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, clientX: e.clientX, clientY: e.clientY }));
});
/* 上滑过半:面板压暗星空的那层渐变加深,「上滑看看」收起 */
box.addEventListener('scroll', function () { box.classList.toggle('up', box.scrollTop > 40); }, { passive: true });
/* 进星空页才拉数据;关掉回到顶部 */
new MutationObserver(function () {
if (page.classList.contains('show')) load(); else { box.scrollTop = 0; box.classList.remove('up'); }
}).observe(page, { attributes: true, attributeFilter: ['class'] });
if (page.classList.contains('show')) load();
})();