38 lines
1.8 KiB
JavaScript
38 lines
1.8 KiB
JavaScript
// Temporary, admin-controlled heads-up shown right above any wallet-connect
|
||
// button while a scanner false-positive is being cleared. Driven by
|
||
// config.walletNotice (admin PATCH): non-empty string = show it, ""/unset =
|
||
// nothing renders. One config flip removes it everywhere, no deploy.
|
||
(function () {
|
||
'use strict';
|
||
fetch('/api/public/config').then(function (r) { return r.json(); }).then(function (c) {
|
||
var msg = (c && c.walletNotice || '').trim();
|
||
if (!msg) return;
|
||
var placed = false;
|
||
function attach() {
|
||
if (placed) return true;
|
||
// The training page has a connect/unlock button under EVERY gated video —
|
||
// show the notice only ONCE (above the first one), never per-video.
|
||
var btns = [].slice.call(document.querySelectorAll('button, a.btn'));
|
||
var btn = btns.filter(function (b) { return /connect|unlock/i.test(b.textContent || ''); })[0];
|
||
if (!btn) return false;
|
||
placed = true;
|
||
var n = document.createElement('div');
|
||
n.className = 'callout';
|
||
n.style.cssText = 'margin:0 0 12px;font-size:13px;line-height:1.5;border-color:rgba(243,190,67,.5)';
|
||
n.innerHTML = 'ℹ️ ' + msg; // admin-authored, same trust level as other config-injected copy
|
||
btn.parentNode.insertBefore(n, btn);
|
||
return true;
|
||
}
|
||
if (attach()) return;
|
||
// Connect/unlock buttons on /my and /training are injected AFTER async data
|
||
// loads — watch the DOM until the first one appears, then stop.
|
||
if (window.MutationObserver) {
|
||
var mo = new MutationObserver(function () { if (attach()) mo.disconnect(); });
|
||
mo.observe(document.body, { childList: true, subtree: true });
|
||
setTimeout(function () { mo.disconnect(); }, 12000);
|
||
} else {
|
||
var t = 0, iv = setInterval(function () { if (attach() || ++t > 12) clearInterval(iv); }, 800);
|
||
}
|
||
}).catch(function () {});
|
||
})();
|