${t.desc}
${t.sub}
${t.loadingTitle}
${t.loadingDesc}
`;
document.body.appendChild(overlay);
const btn = document.getElementById('offerwall-btn');
const safeStart = () => {
const now = Date.now();
if (now - lastClickTs < CLICK_COOLDOWN_MS) return;
lastClickTs = now;
if (flowActive) return;
showRewardedAd(btn);
};
// mobile first
btn.addEventListener('pointerup', safeStart, { passive: true });
btn.addEventListener('touchend', safeStart, { passive: true });
// fallback desktop
btn.addEventListener('click', safeStart);
}
function removeOverlay() {
const overlay = document.getElementById('offerwall-overlay');
if (overlay) overlay.remove();
document.body.classList.remove('offerwall-locked');
}
function setLoadingState(isLoading) {
const loading = document.getElementById('offerwall-loading');
const btn = document.getElementById('offerwall-btn');
if (btn) btn.style.display = isLoading ? 'none' : '';
if (loading) loading.classList.toggle('show', !!isLoading);
}
function setBtnText(btnEl, text) {
try {
const label = btnEl.querySelector('span:last-child');
if (label) label.textContent = text;
} catch (_) {}
}
function loadScriptOnceExact(src, attrs) {
return new Promise((resolve, reject) => {
const existing = document.querySelector('script[data-ow-src="' + src + '"]');
if (existing) {
if (existing.dataset.loaded === '1') return resolve();
existing.addEventListener('load', () => resolve(), { once:true });
existing.addEventListener('error', () => reject(new Error('Failed: ' + src)), { once:true });
return;
}
const s = document.createElement('script');
s.async = true;
s.src = src;
s.dataset.owSrc = src;
if (attrs) Object.keys(attrs).forEach(k => s.setAttribute(k, String(attrs[k])));
s.onload = () => { s.dataset.loaded = '1'; resolve(); };
s.onerror = () => reject(new Error('Failed: ' + src));
document.head.appendChild(s);
});
}
function reinjectScriptExact(src, attrs) {
return new Promise((resolve, reject) => {
document.querySelectorAll('script[src="' + src + '"]').forEach(el => el.remove());
const s = document.createElement('script');
s.async = true;
s.src = src;
if (attrs) Object.keys(attrs).forEach(k => s.setAttribute(k, String(attrs[k])));
s.onload = () => resolve();
s.onerror = () => reject(new Error('Failed: ' + src));
document.head.appendChild(s);
});
}
function loadGPT() {
if (window.googletag && window.googletag.apiReady) return Promise.resolve();
if (!gptLoading) {
gptLoading = loadScriptOnceExact(GPT_SRC, { crossorigin: 'anonymous' })
.then(() => { window.googletag = window.googletag || { cmd: [] }; });
}
return gptLoading;
}
function destroyRewardedSlotSafe() {
try { if (window.googletag && rewardedSlot) window.googletag.destroySlots([rewardedSlot]); } catch (_) {}
rewardedSlot = null;
}
function forceRefreshOnceSoon() {
try {
const gt = window.googletag;
if (!gt || !gt.apiReady) return;
gt.cmd.push(function () {
try {
const pub = gt.pubads && gt.pubads();
if (!pub) return;
setTimeout(() => {
try {
const slots = pub.getSlots ? pub.getSlots() : [];
if (slots && slots.length) {
console.log('[Offerwall] Forcing refresh on slots:', slots.length);
pub.refresh(slots);
} else {
console.warn('[Offerwall] No slots found to refresh (yet).');
}
} catch (e) {
console.warn('[Offerwall] refresh error:', e);
}
}, 300);
} catch (e) {
console.warn('[Offerwall] pubads error:', e);
}
});
} catch (_) {}
}
function finalizePostFlow(hardTimeout, minCloseAt) {
const wait = Math.max(0, minCloseAt - Date.now());
setTimeout(() => {
clearTimeout(hardTimeout);
if (POST_OFFERWALL_MODE === 'redirect') {
window.location.href = REDIRECT_URL;
} else {
removeOverlay();
flowActive = false;
}
}, wait);
}
function startPostOfferwallFlow() {
if (postBooting) return;
postBooting = true;
setLoadingState(true);
const minCloseAt = Date.now() + LOADING_MIN_MS;
const hardTimeout = setTimeout(() => {
console.warn('[Offerwall] post-flow timeout -> fallback');
try {
if (POST_OFFERWALL_MODE === 'redirect') window.location.href = REDIRECT_URL;
else removeOverlay();
} finally {
flowActive = false;
}
}, POST_FLOW_TIMEOUTMS);
if (POST_OFFERWALL_MODE === 'redirect') {
finalizePostFlow(hardTimeout, minCloseAt);
return;
}
Promise.resolve()
.then(() => loadGPT())
.then(() => reinjectScriptExact(OTZ_SRC))
.then(() => forceRefreshOnceSoon())
.then(() => finalizePostFlow(hardTimeout, minCloseAt))
.catch((e) => {
console.warn('[Offerwall] post-flow ads boot failed:', e);
finalizePostFlow(hardTimeout, minCloseAt);
});
}
function showRewardedAd(btnEl) {
if (flowActive) return;
flowActive = true;
btnEl.disabled = true;
setBtnText(btnEl, 'Carregando...');
// watchdog: se travar, continua o fluxo (como você pediu)
const watchdog = setTimeout(() => {
console.warn('[Offerwall] WATCHDOG -> continuando fluxo');
destroyRewardedSlotSafe();
startPostOfferwallFlow();
}, WATCHDOG_MS);
loadGPT()
.then(() => {
window.googletag = window.googletag || { cmd: [] };
googletag.cmd.push(function () {
destroyRewardedSlotSafe();
rewardedSlot = googletag
.defineOutOfPageSlot(adUnitPath, googletag.enums.OutOfPageFormat.REWARDED)
?.addService(googletag.pubads());
// se não conseguir criar slot, continua o fluxo
if (!rewardedSlot) {
console.warn('[Offerwall] Slot rewarded não criado -> continuando fluxo');
clearTimeout(watchdog);
startPostOfferwallFlow();
return;
}
let bought = false;
let completed = false;
// ✅ SE NÃO COMPRAR EM 3.5s -> CONTINUA O FLUXO (pedido do user)
const noBuyFallback = setTimeout(() => {
if (!bought) {
console.warn('[Offerwall] Sem rewardedSlotReady em', FALLBACK_MS, 'ms -> continuando fluxo');
clearTimeout(watchdog);
destroyRewardedSlotSafe();
startPostOfferwallFlow();
}
}, FALLBACK_MS);
const pubads = googletag.pubads();
pubads.addEventListener('rewardedSlotReady', (e) => {
bought = true;
clearTimeout(noBuyFallback);
try { e.makeRewardedVisible(); } catch (_) {}
});
pubads.addEventListener('rewardedSlotGranted', () => {
completed = true;
});
pubads.addEventListener('rewardedSlotClosed', () => {
clearTimeout(noBuyFallback);
clearTimeout(watchdog);
// sempre destrói ao fechar
destroyRewardedSlotSafe();
if (completed) {
// sucesso normal -> continua pós-sucesso
startPostOfferwallFlow();
} else {
// fechou sem grant -> mantém offerwall aberto e permite tentar de novo
console.warn('[Offerwall] Fechou antes do grant -> mantém bloqueado');
flowActive = false;
postBooting = false; // libera tentativa futura
btnEl.disabled = false;
setBtnText(btnEl, t.btn);
}
});
// ✅ no rewarded, só pode isso
googletag.display(rewardedSlot);
});
})
.catch((err) => {
console.warn('[Offerwall] GPT não carregou -> continuando fluxo:', err);
clearTimeout(watchdog);
destroyRewardedSlotSafe();
startPostOfferwallFlow();
});
}
document.addEventListener('DOMContentLoaded', () => {
if (ALWAYS_SHOW_OFFERWALL) createOverlay();
else createOverlay();
});
})();
Ver página(abrir em uma nova aba)