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-багом
|
ситуации, когда localState.read был засорён старым syncPending-багом
|
||||||
(есть ключ локально, нет на сервере, mark_read иначе никогда не уйдёт). */
|
(есть ключ локально, нет на сервере, 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() {
|
function wirePillTracking() {
|
||||||
|
// Hook 1: всплытие click до body. Работает в обычном HTML.
|
||||||
document.body.addEventListener('click', e => {
|
document.body.addEventListener('click', e => {
|
||||||
const tag = e.target && e.target.tagName;
|
const pill = e.target && e.target.closest && e.target.closest('.para-pill[data-para]');
|
||||||
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]');
|
|
||||||
if (!pill) return;
|
if (!pill) return;
|
||||||
const key = pill.dataset.para;
|
console.log('[tracker] клик по пилюле (bubble)', pill.dataset.para);
|
||||||
console.log('[tracker] клик по пилюле', key);
|
recordParaVisit(pill.dataset.para);
|
||||||
localState.last = key;
|
|
||||||
if (!localState.read.includes(key)) {
|
|
||||||
localState.read.push(key);
|
|
||||||
}
|
|
||||||
refreshPillUI(key);
|
|
||||||
refreshCheckUI(key);
|
|
||||||
persist();
|
|
||||||
syncToServer({ mark_read: key });
|
|
||||||
});
|
});
|
||||||
|
// 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) ─────── */
|
/* ── 8. Inject styling for read-pills (subtle green dot) ─────── */
|
||||||
|
|||||||
Reference in New Issue
Block a user