Files

704 lines
30 KiB
JavaScript
Raw Permalink 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.
/* ========== 网址导航 前端交互 ========== */
(function () {
'use strict';
var ENGINE_URLS = {
baidu: 'https://www.baidu.com/s?wd=',
bing: 'https://www.bing.com/search?q=',
google: 'https://www.google.com/search?q=',
sogou: 'https://www.sogou.com/web?query=',
site: '/haonav/search.html?q='
};
var FAV_KEY = 'haonav_fav';
var THEME_KEY = 'haonav_theme';
var BG_KEY = 'haonav_bg';
function $(s, c) { return (c || document).querySelector(s); }
function $all(s, c) { return Array.prototype.slice.call((c || document).querySelectorAll(s)); }
/* ---------- 主题(light / dark / auto 跟随系统) ---------- */
function applyTheme(t) {
var dark;
if (t === 'dark') { dark = true; }
else if (t === 'auto') {
dark = !!(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches);
} else { dark = false; }
if (dark) { document.documentElement.setAttribute('data-theme', 'dark'); }
else { document.documentElement.removeAttribute('data-theme'); }
}
function updateThemeBtn(btn, t) {
if (!btn) { return; }
var map = {
light: { icon: '🌙', title: '当前:浅色(点击切换深色)' },
dark: { icon: '☀️', title: '当前:深色(点击切换跟随系统)' },
auto: { icon: '🌗', title: '当前:跟随系统(点击切换浅色)' }
};
var s = map[t] || map.light;
btn.textContent = s.icon;
btn.title = s.title;
}
function initTheme() {
var t = localStorage.getItem(THEME_KEY) || 'light';
applyTheme(t);
var btn = $('#themeToggle');
updateThemeBtn(btn, t);
// 跟随系统变化时实时刷新(仅 auto 模式生效)
if (window.matchMedia) {
var mq = window.matchMedia('(prefers-color-scheme: dark)');
var onChange = function () {
if ((localStorage.getItem(THEME_KEY) || 'light') === 'auto') { applyTheme('auto'); }
};
if (mq.addEventListener) { mq.addEventListener('change', onChange); }
else if (mq.addListener) { mq.addListener(onChange); }
}
if (btn) {
btn.addEventListener('click', function () {
var cur = localStorage.getItem(THEME_KEY) || 'light';
var next = cur === 'light' ? 'dark' : (cur === 'dark' ? 'auto' : 'light');
localStorage.setItem(THEME_KEY, next);
applyTheme(next);
updateThemeBtn(btn, next);
});
}
}
/* ---------- 背景 ---------- */
function applyBg(v) {
if (v) { document.body.style.background = v; document.body.style.backgroundAttachment = 'fixed'; }
}
function initBg() {
var v = localStorage.getItem(BG_KEY);
if (v) { applyBg(v); }
var sel = $('#bgPicker');
if (sel) {
sel.addEventListener('change', function () {
var v = sel.value;
if (v === 'default') { v = ''; document.body.style.background = ''; localStorage.removeItem(BG_KEY); }
else { applyBg(v); localStorage.setItem(BG_KEY, v); }
});
}
}
/* ---------- 搜索(含站内自动补全下拉) ---------- */
function initSearch() {
var form = $('#searchForm');
if (!form) { return; }
var input = $('#searchInput');
var select = $('#searchEngine');
// 自动补全下拉
var box = document.createElement('div');
box.className = 'suggest-box';
box.id = 'suggestBox';
form.appendChild(box);
var items = [];
var active = -1;
var timer = null;
function hideSuggest() {
box.style.display = 'none';
box.innerHTML = '';
items = [];
active = -1;
}
function highlight() {
$all('.suggest-item', box).forEach(function (el, i) {
el.classList.toggle('active', i === active);
});
var el = box.querySelector('.suggest-item.active');
if (el) { el.scrollIntoView({ block: 'nearest' }); }
}
function goSuggest(id, url) {
hideSuggest();
if (id) { location.href = '/haonav/site/' + id + '.html'; }
else if (url) { window.open(url, '_blank'); }
}
function showSuggest(list) {
if (!list.length) { hideSuggest(); return; }
items = list;
box.innerHTML = list.map(function (it, i) {
var icon = '/haonav/favicon.html?url=' + encodeURI(it.url);
return '<div class="suggest-item' + (i === 0 ? ' active' : '') + '" data-i="' + i + '" data-id="' + it.id + '" data-url="' + encodeURI(it.url) + '">' +
'<img src="' + icon + '" alt=""><span class="s-title">' + esc(it.title) + '</span><span class="s-url">' + esc(it.url) + '</span></div>';
}).join('');
box.style.display = 'block';
active = 0;
$all('.suggest-item', box).forEach(function (el) {
// mousedown 优先于 input blur,避免点击丢失
el.addEventListener('mousedown', function (e) {
e.preventDefault();
goSuggest(el.getAttribute('data-id'), el.getAttribute('data-url'));
});
});
}
function fetchSuggest(q) {
fetch('/haonav/suggest.html?q=' + encodeURIComponent(q))
.then(function (r) { return r.json(); })
.then(function (res) {
if (res.code === 0 && res.data) { showSuggest(res.data); }
else { hideSuggest(); }
})
.catch(function () { hideSuggest(); });
}
input.addEventListener('input', function () {
var q = input.value.trim();
clearTimeout(timer);
if (q.length < 1) { hideSuggest(); return; }
timer = setTimeout(function () { fetchSuggest(q); }, 250);
});
input.addEventListener('keydown', function (e) {
if (box.style.display === 'none') { return; }
if (e.key === 'ArrowDown') {
e.preventDefault();
active = Math.min(items.length - 1, active + 1);
highlight();
} else if (e.key === 'ArrowUp') {
e.preventDefault();
active = Math.max(0, active - 1);
highlight();
} else if (e.key === 'Enter' && active >= 0 && items[active]) {
e.preventDefault();
goSuggest(items[active].id, items[active].url);
} else if (e.key === 'Escape') {
hideSuggest();
}
});
document.addEventListener('click', function (e) {
if (!form.contains(e.target)) { hideSuggest(); }
});
form.addEventListener('submit', function (e) {
e.preventDefault();
hideSuggest();
var q = input.value.trim();
if (!q) { input.focus(); return; }
var engine = select ? select.value : 'baidu';
if (engine === 'site') {
location.href = '/haonav/search.html?q=' + encodeURIComponent(q);
return;
}
var url = (ENGINE_URLS[engine] || ENGINE_URLS.baidu) + encodeURIComponent(q);
window.open(url, '_blank');
});
}
/* ---------- 网站评分(详情页星星组件) ---------- */
function paintStars(stars, n) {
stars.forEach(function (s, i) { s.classList.toggle('on', i < n); });
}
function submitRate(id, score, tip) {
fetch('/haonav/rate.html', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
credentials: 'same-origin',
body: JSON.stringify({ id: id, score: score })
}).then(function (r) { return r.json(); }).then(function (res) {
if (res.code === 0) {
if ($('#ratingScore')) { $('#ratingScore').textContent = res.data.rating; }
if ($('#ratingCount')) { $('#ratingCount').textContent = res.data.rating_count + ' 人评分'; }
paintStars($all('.star'), Math.round(res.data.rating));
if (tip) { tip.textContent = '感谢评分!'; }
} else if (res.code === 401) {
if (tip) { tip.textContent = '请先登录后再评分'; }
if (typeof window.openLoginModal === 'function') { window.openLoginModal(); }
} else {
if (tip) { tip.textContent = res.message || '评分失败'; }
}
}).catch(function () { if (tip) { tip.textContent = '网络错误,请稍后重试'; } });
}
function initRating() {
var box = $('#ratingBox');
if (!box) { return; }
var id = box.getAttribute('data-id');
var stars = $all('.star', box);
var tip = $('#ratingTip');
function base() { return Math.round(parseFloat(($('#ratingScore') ? $('#ratingScore').textContent : '0')) || 0); }
paintStars(stars, base());
stars.forEach(function (s) {
s.addEventListener('mouseenter', function () {
paintStars(stars, parseInt(s.getAttribute('data-score'), 10));
});
s.addEventListener('click', function () {
submitRate(id, parseInt(s.getAttribute('data-score'), 10), tip);
});
});
box.addEventListener('mouseleave', function () { paintStars(stars, base()); });
}
/* ---------- 站内搜索结果(搜索页) ---------- */
function initSiteSearch() {
var box = $('#searchResults');
if (!box) { return; }
var input = $('#searchInput');
var q = input ? input.value.trim() : '';
function render(list) {
if (!list.length) {
box.innerHTML = '<p style="color:var(--nav-muted);padding:20px;">没有找到相关网址,换个关键词试试~</p>';
return;
}
box.innerHTML = list.map(function (it) {
var icon = it.show_icon || it.favicon || it.icon || '/static/haonav/img/default.png';
return '<a class="search-item" href="/haonav/site/' + it.id + '.html" target="_blank">' +
'<span class="rank-icon"><img src="' + icon + '" alt=""></span>' +
'<span class="rank-meta"><h4>' + esc(it.title) + '</h4><p>' + esc(it.description || it.url) + '</p>' +
(it.rating_count ? '<span class="rank-rating">⭐ ' + it.rating + ' (' + it.rating_count + ')</span>' : '') +
'</span>' +
'</a>';
}).join('');
}
if (q) {
fetch('/haonav/search.html?ajax=1&q=' + encodeURIComponent(q))
.then(function (r) { return r.json(); })
.then(function (res) { render(res.data || []); })
.catch(function () { box.innerHTML = '<p style="color:var(--nav-muted)">搜索失败</p>'; });
} else {
render([]);
}
}
/* ---------- 我的导航(收藏:登录云端同步 / 未登录本地存储) ---------- */
var CLOUD = false; // 是否已登录、使用云端
var favCache = []; // 当前收藏内存镜像(云端或本地)
function localGet() {
try { return JSON.parse(localStorage.getItem(FAV_KEY)) || []; }
catch (e) { return []; }
}
function localSet(list) { localStorage.setItem(FAV_KEY, JSON.stringify(list)); }
function api(action, body) {
return fetch('/haonav/favorite/' + action, {
method: body ? 'POST' : 'GET',
credentials: 'same-origin',
headers: body ? { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' } : { 'X-Requested-With': 'XMLHttpRequest' },
body: body ? JSON.stringify(body) : undefined
}).then(function (r) { return r.json(); });
}
function setTip(text) { var t = $('#myNavTip'); if (t) { t.textContent = text; } }
function renderFav() {
var list = $('#myNavList');
var empty = $('#myNavEmpty');
if (!list) { return; }
if (!favCache.length) {
list.innerHTML = '';
if (empty) { empty.style.display = 'block'; }
return;
}
if (empty) { empty.style.display = 'none'; }
list.innerHTML = favCache.map(function (it, i) {
return '<div class="mynav-item" draggable="true" data-idx="' + i + '">' +
'<img src="' + (it.icon || '/static/haonav/img/default.png') + '" alt="">' +
'<a href="' + encodeURI(it.url) + '" target="_blank" title="' + esc(it.title) + '">' + esc(it.title) + '</a>' +
'<span class="del" data-idx="' + i + '" title="移除">✕</span>' +
'</div>';
}).join('');
bindFavDrag(list);
}
function persistOrder() {
if (CLOUD) {
var ids = favCache.map(function (x) { return x.id; }).filter(Boolean);
api('sort', { ids: ids });
} else {
localSet(favCache);
}
}
function bindFavDrag(list) {
var dragEl = null;
$all('.mynav-item', list).forEach(function (el) {
el.addEventListener('dragstart', function () { dragEl = el; el.style.opacity = '.4'; });
el.addEventListener('dragend', function () { el.style.opacity = '1'; dragEl = null; });
el.addEventListener('dragover', function (e) { e.preventDefault(); });
el.addEventListener('drop', function (e) {
e.preventDefault();
if (!dragEl || dragEl === el) { return; }
var from = parseInt(dragEl.getAttribute('data-idx'), 10);
var to = parseInt(el.getAttribute('data-idx'), 10);
var moved = favCache.splice(from, 1)[0];
favCache.splice(to, 0, moved);
renderFav();
persistOrder();
});
});
$all('.del', list).forEach(function (del) {
del.addEventListener('click', function () {
var idx = parseInt(del.getAttribute('data-idx'), 10);
var it = favCache[idx];
favCache.splice(idx, 1);
renderFav();
if (CLOUD) { api('remove', { id: it && it.id, url: it && it.url }); }
else { localSet(favCache); }
});
});
}
function addFav(data) {
if (favCache.some(function (x) { return x.url === data.url; })) {
alert('已经在我的导航里啦');
return;
}
if (CLOUD) {
api('add', data).then(function (res) {
if (res.code === 0) {
data.id = (res.data && res.data.id) || 0;
favCache.push(data);
renderFav();
} else if (res.code === 401) {
CLOUD = false; addFav(data);
} else { alert(res.message || '收藏失败'); }
}).catch(function () { alert('网络错误'); });
} else {
favCache.push(data);
localSet(favCache);
renderFav();
}
}
function initFav() {
// 先本地渲染,随后尝试云端
favCache = localGet();
renderFav();
api('list').then(function (res) {
if (res.code === 0) {
CLOUD = true;
var local = localGet();
var cloud = res.data || [];
if (local.length) {
// 登录后把本地收藏合并上云,只做一次
api('merge', { items: local }).then(function (m) {
favCache = (m.code === 0 ? m.data : cloud) || [];
localStorage.removeItem(FAV_KEY);
setTip('(已登录,云端同步 · 可拖拽排序)');
renderFav();
});
} else {
favCache = cloud;
setTip('(已登录,云端同步 · 可拖拽排序)');
renderFav();
}
} else {
// 未登录:保持本地
CLOUD = false;
setTip('(未登录,仅存本机;登录后可跨设备同步)');
}
}).catch(function () { CLOUD = false; });
document.addEventListener('click', function (e) {
var btn = e.target.closest && e.target.closest('.js-fav');
if (btn) {
addFav({
id: btn.getAttribute('data-id'),
title: btn.getAttribute('data-title'),
url: btn.getAttribute('data-url'),
icon: btn.getAttribute('data-icon')
});
}
});
}
/* ---------- 收藏夹分享(登录用户生成只读分享链接) ---------- */
function initFavShare() {
var btn = $('#favShareBtn');
var mask = $('#favShareMask');
if (!btn || !mask) { return; }
var toggle = $('#favShareToggle');
var titleInp = $('#favShareTitle');
var linkBox = $('#favShareLinkBox');
var linkInp = $('#favShareLink');
var viewsEl = $('#favShareViews');
var msg = $('#favShareMsg');
function setMsg(t) { if (msg) { msg.textContent = t || ''; } }
function fill(d) {
toggle.checked = !!d.enabled;
titleInp.value = d.title || '';
linkInp.value = d.url || '';
if (viewsEl) { viewsEl.textContent = d.views || 0; }
linkBox.style.display = d.enabled ? 'block' : 'none';
}
function save(extra) {
var body = { enabled: toggle.checked ? 1 : 0, title: titleInp.value.trim() };
if (extra && extra.reset) { body.reset = 1; }
setMsg('保存中…');
api('sharesave', body).then(function (res) {
if (res.code === 0) { fill(res.data); setMsg('已保存'); }
else if (res.code === 401) { setMsg('请先登录'); if (typeof window.openLoginModal === 'function') { window.openLoginModal(); } }
else { setMsg(res.message || '保存失败'); }
}).catch(function () { setMsg('网络错误'); });
}
btn.addEventListener('click', function () {
setMsg('加载中…');
mask.classList.add('show');
api('share').then(function (res) {
if (res.code === 0) { fill(res.data); setMsg(''); }
else if (res.code === 401) {
setMsg('登录后即可生成分享链接');
linkBox.style.display = 'none';
if (typeof window.openLoginModal === 'function') { window.openLoginModal(); }
} else { setMsg(res.message || '加载失败'); }
}).catch(function () { setMsg('网络错误'); });
});
toggle.addEventListener('change', function () { save(); });
titleInp.addEventListener('blur', function () { if (toggle.checked) { save(); } });
var copyBtn = $('#favShareCopy');
if (copyBtn) {
copyBtn.addEventListener('click', function () {
linkInp.select();
try { document.execCommand('copy'); setMsg('已复制链接'); }
catch (e) {
if (navigator.clipboard) { navigator.clipboard.writeText(linkInp.value); setMsg('已复制链接'); }
}
});
}
var resetBtn = $('#favShareReset');
if (resetBtn) {
resetBtn.addEventListener('click', function (e) {
e.preventDefault();
if (confirm('重置后旧链接将立即失效,确定?')) { save({ reset: true }); }
});
}
mask.addEventListener('click', function (e) {
if (e.target === mask || e.target.classList.contains('close')) { mask.classList.remove('show'); }
});
}
/* ---------- 顶部小组件:天气 + 实时热搜 ---------- */
function initWeather() {
var box = $('#weatherWidget');
if (!box) { return; }
fetch('/haonav/widget/weather', { credentials: 'same-origin' })
.then(function (r) { return r.json(); })
.then(function (res) {
var d = res.data;
if (res.code !== 0 || !d || !d.city) { return; }
$('#wCity').textContent = d.city;
$('#wType').textContent = d.type || '';
$('#wTemp').textContent = (d.low || '') + ' ~ ' + (d.high || '');
if (d.tips) { $('#wTips').textContent = d.tips; }
box.style.display = 'flex';
}).catch(function () { });
}
function loadHot(src) {
var box = $('#hotSearchWidget');
var ol = $('#hotSearchList');
if (!ol) { return; }
fetch('/haonav/widget/hot?source=' + encodeURIComponent(src), { credentials: 'same-origin' })
.then(function (r) { return r.json(); })
.then(function (res) {
var list = res.data || [];
if (res.code !== 0 || !list.length) {
if (!box.dataset.shown) { box.style.display = 'none'; }
return;
}
box.style.display = 'block';
box.dataset.shown = '1';
ol.innerHTML = list.map(function (it, i) {
var link = it.url
? '<a href="' + encodeURI(it.url) + '" target="_blank" title="' + esc(it.title) + '">' + esc(it.title) + '</a>'
: '<a href="https://www.baidu.com/s?wd=' + encodeURIComponent(it.title) + '" target="_blank">' + esc(it.title) + '</a>';
return '<li><i class="rk">' + (i + 1) + '</i>' + link + '</li>';
}).join('');
}).catch(function () { });
}
function initHotSearch() {
var tabs = $('#hsTabs');
if (!tabs) { return; }
var def = 'baidu';
loadHot(def);
tabs.addEventListener('click', function (e) {
var a = e.target.closest && e.target.closest('a[data-src]');
if (!a) { return; }
$all('a', tabs).forEach(function (x) { x.classList.remove('active'); });
a.classList.add('active');
loadHot(a.getAttribute('data-src'));
});
}
/* ---------- 二维码 ---------- */
function initQr() {
var mask = $('#qrMask');
if (!mask) { return; }
var img = $('#qrImg');
var txt = $('#qrText');
var close = function () { mask.classList.remove('show'); };
mask.addEventListener('click', function (e) { if (e.target === mask || e.target.classList.contains('close')) { close(); } });
document.addEventListener('click', function (e) {
var btn = e.target.closest && e.target.closest('.js-qr');
if (btn) {
var url = btn.getAttribute('data-url');
img.src = 'https://api.qrserver.com/v1/create-qr-code/?size=220x220&data=' + encodeURIComponent(url);
txt.textContent = url;
mask.classList.add('show');
}
});
}
/* ---------- 键盘快捷键 ---------- */
function initShortcuts() {
document.addEventListener('keydown', function (e) {
var tag = (e.target.tagName || '').toLowerCase();
if (tag === 'input' || tag === 'textarea' || tag === 'select') { return; }
if (e.key === '/') {
var inp = $('#searchInput');
if (inp) { e.preventDefault(); inp.focus(); }
return;
}
if (/^[1-9]$/.test(e.key)) {
var blocks = $all('.category-block');
var idx = parseInt(e.key, 10) - 1;
if (blocks[idx]) { blocks[idx].scrollIntoView({ behavior: 'smooth', block: 'start' }); }
}
});
}
/* ---------- 投稿表单 ---------- */
function initSubmit() {
var form = $('#submitForm');
if (!form) { return; }
form.addEventListener('submit', function (e) {
e.preventDefault();
var msg = $('#submitMsg');
var fd = new FormData(form);
fetch('/haonav/submit.html', { method: 'POST', body: fd, headers: { 'X-Requested-With': 'XMLHttpRequest' } })
.then(function (r) { return r.json(); })
.then(function (res) {
msg.textContent = res.msg || (res.code === 0 ? '提交成功' : '提交失败');
msg.className = 'form-msg ' + (res.code === 0 ? 'ok' : 'err');
if (res.code === 0) { form.reset(); }
})
.catch(function () { msg.textContent = '网络错误,请稍后重试'; msg.className = 'form-msg err'; });
});
}
/* ---------- 网站截图悬停预览 ---------- */
function initSnapshotPreview() {
if (!window.matchMedia || !window.matchMedia('(hover: hover)').matches) { return; }
var cards = $all('.website-card[data-sid]');
if (!cards.length) { return; }
var tip = document.createElement('div');
tip.id = 'snapPreview';
tip.style.cssText = 'position:fixed;z-index:9999;display:none;width:320px;padding:6px;background:var(--nav-card-bg,#fff);border-radius:10px;box-shadow:0 8px 30px rgba(0,0,0,.25);pointer-events:none;';
var img = document.createElement('img');
img.style.cssText = 'width:100%;border-radius:6px;display:block;min-height:60px;background:#f0f1f5;';
tip.appendChild(img);
document.body.appendChild(tip);
var timer = null;
function hide() { clearTimeout(timer); timer = null; tip.style.display = 'none'; }
document.addEventListener('mouseover', function (e) {
var card = e.target.closest && e.target.closest('.website-card[data-sid]');
if (!card) { return; }
var sid = card.getAttribute('data-sid');
clearTimeout(timer);
timer = setTimeout(function () {
img.style.opacity = '0';
img.onload = function () {
// 默认占位小图不展示,只有真实截图(宽>120px)才显示
if (img.naturalWidth <= 120) { hide(); return; }
img.style.opacity = '1';
};
img.src = '/haonav/snapshot.html?id=' + sid;
var rect = card.getBoundingClientRect();
var left = rect.right + 12;
if (left + 330 > window.innerWidth) { left = rect.left - 332; }
if (left < 4) { left = 4; }
var top = Math.min(rect.top, window.innerHeight - 260);
tip.style.left = left + 'px';
tip.style.top = Math.max(4, top) + 'px';
tip.style.display = 'block';
}, 450);
});
document.addEventListener('mouseout', function (e) {
var card = e.target.closest && e.target.closest('.website-card[data-sid]');
if (card) { hide(); }
});
}
/* ---------- PWAService Worker + 安装 + 设为首页引导 ---------- */
function initPwa() {
// 仅在导航首页(有 manifest)注册
if (document.querySelector('link[rel="manifest"]') && 'serviceWorker' in navigator) {
navigator.serviceWorker.register('/haonav/sw.html', { scope: '/haonav/' }).catch(function () { });
}
var installBtn = $('#pwaInstallBtn');
var deferredPrompt = null;
window.addEventListener('beforeinstallprompt', function (e) {
e.preventDefault();
deferredPrompt = e;
if (installBtn) { installBtn.style.display = ''; }
});
if (installBtn) {
installBtn.addEventListener('click', function () {
if (!deferredPrompt) { return; }
deferredPrompt.prompt();
deferredPrompt.userChoice.then(function () {
deferredPrompt = null;
installBtn.style.display = 'none';
});
});
}
window.addEventListener('appinstalled', function () {
if (installBtn) { installBtn.style.display = 'none'; }
});
var homeBtn = $('#setHomeBtn');
var mask = $('#homeTipMask');
if (homeBtn && mask) {
homeBtn.addEventListener('click', function () {
var u = $('#homeTipUrl');
if (u) { u.textContent = location.origin + '/haonav/index.html'; }
mask.classList.add('show');
});
mask.addEventListener('click', function (e) {
if (e.target === mask || e.target.classList.contains('close')) { mask.classList.remove('show'); }
});
}
}
/* ---------- 惰性死链巡检 ping(服务端有缓存锁限频,前端只管发) ---------- */
function initAutoCheck() {
if (!$('#searchForm')) { return; } // 仅导航页面触发
setTimeout(function () {
fetch('/haonav/task/autocheck', { credentials: 'same-origin', keepalive: true }).catch(function () { });
}, 5000);
}
function esc(s) {
return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
});
}
document.addEventListener('DOMContentLoaded', function () {
initTheme();
initBg();
initSearch();
initSiteSearch();
initFav();
initFavShare();
initQr();
initShortcuts();
initSubmit();
initRating();
initWeather();
initHotSearch();
initSnapshotPreview();
initPwa();
initAutoCheck();
});
})();