fix(tracker): тройной хук — bubble, capture, monkey-patch setParaTab
Юзер докладывает, что клик по пилюле не вызывает body click handler (никаких логов после клика). Возможные причины: capture-listener расширения браузера со stopPropagation, CSS overlay, что-то ещё. Чтобы гарантированно ловить клики ВНЕ зависимости от bubble-цепочки: 1) Bubble click на body (как было) 2) Capture click на document (фаза до bubble) 3) Monkey-patch window.setParaTab — функцию, которую chemistry-9 и physics-9 зовут inline через onclick. Перехват на уровне JS-функции работает даже если event-стек сломан. Защита от двойного срабатывания: pill.__tbVisited флаг на 100мс. Если setParaTab определяется позже tracker'а — короткий poll 20*100мс.
This commit is contained in:
@@ -225,24 +225,64 @@
|
||||
не добавит дубликат. Эта «избыточность» лечит самовосстановлением
|
||||
ситуации, когда localState.read был засорён старым syncPending-багом
|
||||
(есть ключ локально, нет на сервере, mark_read иначе никогда не уйдёт). */
|
||||
function recordParaVisit(key) {
|
||||
if (!key) return;
|
||||
localState.last = key;
|
||||
if (!localState.read.includes(key)) {
|
||||
localState.read.push(key);
|
||||
}
|
||||
refreshPillUI(key);
|
||||
refreshCheckUI(key);
|
||||
persist();
|
||||
syncToServer({ mark_read: key });
|
||||
}
|
||||
|
||||
function wirePillTracking() {
|
||||
// Hook 1: всплытие click до body. Работает в обычном HTML.
|
||||
document.body.addEventListener('click', e => {
|
||||
const tag = e.target && e.target.tagName;
|
||||
const cls = e.target && e.target.className;
|
||||
console.log('[tracker] click event target:', tag, '| class:', cls, '| has .para-pill[data-para] up the tree:', !!e.target.closest('.para-pill[data-para]'));
|
||||
const pill = e.target.closest('.para-pill[data-para]');
|
||||
const pill = e.target && e.target.closest && e.target.closest('.para-pill[data-para]');
|
||||
if (!pill) return;
|
||||
const key = pill.dataset.para;
|
||||
console.log('[tracker] клик по пилюле', key);
|
||||
localState.last = key;
|
||||
if (!localState.read.includes(key)) {
|
||||
localState.read.push(key);
|
||||
}
|
||||
refreshPillUI(key);
|
||||
refreshCheckUI(key);
|
||||
persist();
|
||||
syncToServer({ mark_read: key });
|
||||
console.log('[tracker] клик по пилюле (bubble)', pill.dataset.para);
|
||||
recordParaVisit(pill.dataset.para);
|
||||
});
|
||||
// Hook 2: capture-фаза (ловит до того, как кто-то остановит propagation).
|
||||
document.addEventListener('click', e => {
|
||||
const pill = e.target && e.target.closest && e.target.closest('.para-pill[data-para]');
|
||||
if (!pill) return;
|
||||
// Защита от двойного срабатывания — отметим pill сразу.
|
||||
if (pill.__tbVisited) return;
|
||||
pill.__tbVisited = true;
|
||||
setTimeout(() => { pill.__tbVisited = false; }, 100);
|
||||
console.log('[tracker] клик по пилюле (capture)', pill.dataset.para);
|
||||
recordParaVisit(pill.dataset.para);
|
||||
}, true);
|
||||
// Hook 3: monkey-patch setParaTab — кликом по пилюле химия/физика 9 вызывают
|
||||
// inline onclick="setParaTab('pN')". Перехват напрямую = работает даже если
|
||||
// event-bubbling сломан расширением браузера или CSS overlay.
|
||||
function patchSetParaTab() {
|
||||
if (typeof window.setParaTab !== 'function' || window.setParaTab.__tbPatched) return;
|
||||
const orig = window.setParaTab;
|
||||
const wrapped = function (para) {
|
||||
try {
|
||||
if (para && /^p\d+$/i.test(String(para))) {
|
||||
console.log('[tracker] setParaTab перехвачен', para);
|
||||
recordParaVisit(String(para));
|
||||
}
|
||||
} catch (e) { console.warn('[tracker] patch error:', e); }
|
||||
return orig.apply(this, arguments);
|
||||
};
|
||||
wrapped.__tbPatched = true;
|
||||
window.setParaTab = wrapped;
|
||||
console.log('[tracker] setParaTab успешно обёрнут');
|
||||
}
|
||||
patchSetParaTab();
|
||||
// Если страница определяет setParaTab позже — поймаем через короткие опросы.
|
||||
let tries = 0;
|
||||
const ivl = setInterval(() => {
|
||||
patchSetParaTab();
|
||||
if (typeof window.setParaTab === 'function' && window.setParaTab.__tbPatched) clearInterval(ivl);
|
||||
if (++tries > 20) clearInterval(ivl);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
/* ── 8. Inject styling for read-pills (subtle green dot) ─────── */
|
||||
|
||||
Reference in New Issue
Block a user