fix: 返回列表后未读邮件状态不更新(BFCache 静默同步) #9
@@ -489,3 +489,127 @@
|
|||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{define "listjs"}}
|
||||||
|
<script>
|
||||||
|
(function () {
|
||||||
|
var searchInput = document.getElementById('mail-search');
|
||||||
|
var rows = Array.prototype.slice.call(document.querySelectorAll('.mail-row'));
|
||||||
|
var selectAll = document.getElementById('select-all');
|
||||||
|
var btnDelete = document.getElementById('btn-delete');
|
||||||
|
|
||||||
|
// 行点击跳转(复选框 / 行内删除按钮除外)
|
||||||
|
rows.forEach(function (row) {
|
||||||
|
row.addEventListener('click', function (e) {
|
||||||
|
if (e.target.closest('.cell-check') || e.target.closest('.row-del')) return;
|
||||||
|
var link = row.querySelector('.cell-subject');
|
||||||
|
if (link) window.location.href = link.getAttribute('href');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 全选
|
||||||
|
selectAll && selectAll.addEventListener('change', function () {
|
||||||
|
rows.forEach(function (row) {
|
||||||
|
var cb = row.querySelector('.row-check');
|
||||||
|
cb.checked = selectAll.checked;
|
||||||
|
row.classList.toggle('selected', cb.checked);
|
||||||
|
});
|
||||||
|
updateDeleteState();
|
||||||
|
});
|
||||||
|
rows.forEach(function (row) {
|
||||||
|
var cb = row.querySelector('.row-check');
|
||||||
|
cb.addEventListener('change', function () {
|
||||||
|
row.classList.toggle('selected', cb.checked);
|
||||||
|
if (!cb.checked && selectAll) selectAll.checked = false;
|
||||||
|
updateDeleteState();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateDeleteState() {
|
||||||
|
if (!btnDelete) return;
|
||||||
|
var n = rows.filter(function (r) { return r.isConnected && r.querySelector('.row-check').checked; }).length;
|
||||||
|
btnDelete.disabled = n === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量删除
|
||||||
|
btnDelete && btnDelete.addEventListener('click', function () {
|
||||||
|
var ids = rows.filter(function (r) { return r.isConnected && r.querySelector('.row-check').checked; })
|
||||||
|
.map(function (r) { return r.dataset.id; });
|
||||||
|
if (!ids.length) return;
|
||||||
|
if (!confirm('确定要删除选中的 ' + ids.length + ' 封邮件吗?')) return;
|
||||||
|
var done = 0;
|
||||||
|
ids.forEach(function (id) {
|
||||||
|
fetch('/mail/delete/' + id, { method: 'POST', body: new FormData() })
|
||||||
|
.then(function () { if (++done === ids.length) window.location.reload(); })
|
||||||
|
.catch(function () { if (++done === ids.length) window.location.reload(); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 刷新
|
||||||
|
var btnRefresh = document.getElementById('btn-refresh');
|
||||||
|
btnRefresh && btnRefresh.addEventListener('click', function () { window.location.reload(); });
|
||||||
|
|
||||||
|
// 搜索过滤(发件人 / 主题 / 摘要)
|
||||||
|
searchInput && searchInput.addEventListener('input', function () {
|
||||||
|
var q = searchInput.value.trim().toLowerCase();
|
||||||
|
rows.forEach(function (row) {
|
||||||
|
if (!row.isConnected) return;
|
||||||
|
var text = row.textContent.toLowerCase();
|
||||||
|
row.style.display = (!q || text.indexOf(q) !== -1) ? '' : 'none';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 从 BFCache(往返缓存)恢复时静默同步最新列表状态:
|
||||||
|
// 阅读页已把邮件标记为已读/删除,恢复的旧 DOM 需要与服务端对齐,
|
||||||
|
// 避免“返回后仍是未读/已删邮件仍显示”。
|
||||||
|
// 真实浏览器在 BFCache 恢复时会触发 pageshow(persisted=true);
|
||||||
|
// visibilitychange 作为兜底(页面重新可见时也同步一次)。
|
||||||
|
var syncing = false;
|
||||||
|
function syncFromServer(forceReloadOnError) {
|
||||||
|
if (syncing) return;
|
||||||
|
syncing = true;
|
||||||
|
fetch(window.location.href, { headers: { 'Accept': 'text/html' }, credentials: 'same-origin' })
|
||||||
|
.then(function (r) { return r.text(); })
|
||||||
|
.then(function (html) {
|
||||||
|
var doc = new DOMParser().parseFromString(html, 'text/html');
|
||||||
|
var fresh = {};
|
||||||
|
doc.querySelectorAll('.mail-row').forEach(function (r) { fresh[r.dataset.id] = r.classList.contains('unread'); });
|
||||||
|
rows.forEach(function (row) {
|
||||||
|
var id = row.dataset.id;
|
||||||
|
if (!(id in fresh)) { row.remove(); return; } // 已被删除
|
||||||
|
row.classList.toggle('unread', fresh[id]);
|
||||||
|
var wrap = row.querySelector('.cell-subject-wrap');
|
||||||
|
var dot = row.querySelector('.unread-dot');
|
||||||
|
if (fresh[id] && !dot && wrap) {
|
||||||
|
var s = document.createElement('span');
|
||||||
|
s.className = 'unread-dot';
|
||||||
|
wrap.insertBefore(s, wrap.firstChild);
|
||||||
|
} else if (!fresh[id] && dot) {
|
||||||
|
dot.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 同步“共 N 封”与侧栏未读角标
|
||||||
|
var total = doc.querySelector('.page-info');
|
||||||
|
var curTotal = document.querySelector('.page-info');
|
||||||
|
if (total && curTotal) curTotal.textContent = total.textContent;
|
||||||
|
var badge = doc.querySelector('.folder.active .badge');
|
||||||
|
var curBadge = document.querySelector('.folder.active .badge');
|
||||||
|
if (badge && curBadge) curBadge.textContent = badge.textContent;
|
||||||
|
else if (!badge && curBadge) curBadge.remove();
|
||||||
|
})
|
||||||
|
.catch(function () {
|
||||||
|
// BFCache 恢复时 DOM 是旧的,同步失败只能整页刷新兜底;
|
||||||
|
// 标签页切回触发的同步失败则静默忽略(可能只是离线)。
|
||||||
|
if (forceReloadOnError) window.location.reload();
|
||||||
|
})
|
||||||
|
.then(function () { syncing = false; });
|
||||||
|
}
|
||||||
|
window.addEventListener('pageshow', function (e) {
|
||||||
|
if (e.persisted) syncFromServer(true);
|
||||||
|
});
|
||||||
|
document.addEventListener('visibilitychange', function () {
|
||||||
|
if (document.visibilityState === 'visible') syncFromServer(false);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{{end}}
|
||||||
@@ -87,68 +87,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
{{template "listjs" .}}
|
||||||
(function () {
|
|
||||||
var searchInput = document.getElementById('mail-search');
|
|
||||||
var rows = Array.prototype.slice.call(document.querySelectorAll('.mail-row'));
|
|
||||||
var selectAll = document.getElementById('select-all');
|
|
||||||
var btnDelete = document.getElementById('btn-delete');
|
|
||||||
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
row.addEventListener('click', function (e) {
|
|
||||||
if (e.target.closest('.cell-check') || e.target.closest('.row-del')) return;
|
|
||||||
window.location.href = row.querySelector('.cell-subject').getAttribute('href');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
selectAll && selectAll.addEventListener('change', function () {
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
var cb = row.querySelector('.row-check');
|
|
||||||
cb.checked = selectAll.checked;
|
|
||||||
row.classList.toggle('selected', cb.checked);
|
|
||||||
});
|
|
||||||
updateDeleteState();
|
|
||||||
});
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
var cb = row.querySelector('.row-check');
|
|
||||||
cb.addEventListener('change', function () {
|
|
||||||
row.classList.toggle('selected', cb.checked);
|
|
||||||
if (!cb.checked && selectAll) selectAll.checked = false;
|
|
||||||
updateDeleteState();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateDeleteState() {
|
|
||||||
if (!btnDelete) return;
|
|
||||||
var n = rows.filter(function (r) { return r.querySelector('.row-check').checked; }).length;
|
|
||||||
btnDelete.disabled = n === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
btnDelete && btnDelete.addEventListener('click', function () {
|
|
||||||
var ids = rows.filter(function (r) { return r.querySelector('.row-check').checked; })
|
|
||||||
.map(function (r) { return r.dataset.id; });
|
|
||||||
if (!ids.length) return;
|
|
||||||
if (!confirm('确定要删除选中的 ' + ids.length + ' 封邮件吗?')) return;
|
|
||||||
var done = 0;
|
|
||||||
ids.forEach(function (id) {
|
|
||||||
fetch('/mail/delete/' + id, { method: 'POST', body: new FormData() })
|
|
||||||
.then(function () { if (++done === ids.length) window.location.reload(); })
|
|
||||||
.catch(function () { if (++done === ids.length) window.location.reload(); });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var btnRefresh = document.getElementById('btn-refresh');
|
|
||||||
btnRefresh && btnRefresh.addEventListener('click', function () { window.location.reload(); });
|
|
||||||
|
|
||||||
searchInput && searchInput.addEventListener('input', function () {
|
|
||||||
var q = searchInput.value.trim().toLowerCase();
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
var text = row.textContent.toLowerCase();
|
|
||||||
row.style.display = (!q || text.indexOf(q) !== -1) ? '' : 'none';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -82,75 +82,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
{{template "listjs" .}}
|
||||||
(function () {
|
|
||||||
var searchInput = document.getElementById('mail-search');
|
|
||||||
var rows = Array.prototype.slice.call(document.querySelectorAll('.mail-row'));
|
|
||||||
var selectAll = document.getElementById('select-all');
|
|
||||||
var btnDelete = document.getElementById('btn-delete');
|
|
||||||
|
|
||||||
// 行点击跳转(复选框除外)
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
row.addEventListener('click', function (e) {
|
|
||||||
if (e.target.closest('.cell-check')) return;
|
|
||||||
window.location.href = row.querySelector('.cell-subject').getAttribute('href');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 全选
|
|
||||||
selectAll && selectAll.addEventListener('change', function () {
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
var cb = row.querySelector('.row-check');
|
|
||||||
cb.checked = selectAll.checked;
|
|
||||||
row.classList.toggle('selected', cb.checked);
|
|
||||||
});
|
|
||||||
updateDeleteState();
|
|
||||||
});
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
var cb = row.querySelector('.row-check');
|
|
||||||
cb.addEventListener('change', function () {
|
|
||||||
row.classList.toggle('selected', cb.checked);
|
|
||||||
if (!cb.checked && selectAll) selectAll.checked = false;
|
|
||||||
updateDeleteState();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateDeleteState() {
|
|
||||||
if (!btnDelete) return;
|
|
||||||
var n = rows.filter(function (r) { return r.querySelector('.row-check').checked; }).length;
|
|
||||||
btnDelete.disabled = n === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 批量删除
|
|
||||||
btnDelete && btnDelete.addEventListener('click', function () {
|
|
||||||
var ids = rows.filter(function (r) { return r.querySelector('.row-check').checked; })
|
|
||||||
.map(function (r) { return r.dataset.id; });
|
|
||||||
if (!ids.length) return;
|
|
||||||
if (!confirm('确定要删除选中的 ' + ids.length + ' 封邮件吗?')) return;
|
|
||||||
var done = 0;
|
|
||||||
ids.forEach(function (id) {
|
|
||||||
var fd = new FormData();
|
|
||||||
fd.append('_method', 'DELETE');
|
|
||||||
fetch('/mail/delete/' + id, { method: 'POST', body: fd })
|
|
||||||
.then(function () { if (++done === ids.length) window.location.reload(); })
|
|
||||||
.catch(function () { if (++done === ids.length) window.location.reload(); });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 刷新
|
|
||||||
var btnRefresh = document.getElementById('btn-refresh');
|
|
||||||
btnRefresh && btnRefresh.addEventListener('click', function () { window.location.reload(); });
|
|
||||||
|
|
||||||
// 搜索过滤(发件人 / 主题 / 摘要)
|
|
||||||
searchInput && searchInput.addEventListener('input', function () {
|
|
||||||
var q = searchInput.value.trim().toLowerCase();
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
var text = row.textContent.toLowerCase();
|
|
||||||
row.style.display = (!q || text.indexOf(q) !== -1) ? '' : 'none';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -87,68 +87,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
{{template "listjs" .}}
|
||||||
(function () {
|
|
||||||
var searchInput = document.getElementById('mail-search');
|
|
||||||
var rows = Array.prototype.slice.call(document.querySelectorAll('.mail-row'));
|
|
||||||
var selectAll = document.getElementById('select-all');
|
|
||||||
var btnDelete = document.getElementById('btn-delete');
|
|
||||||
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
row.addEventListener('click', function (e) {
|
|
||||||
if (e.target.closest('.cell-check') || e.target.closest('.row-del')) return;
|
|
||||||
window.location.href = row.querySelector('.cell-subject').getAttribute('href');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
selectAll && selectAll.addEventListener('change', function () {
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
var cb = row.querySelector('.row-check');
|
|
||||||
cb.checked = selectAll.checked;
|
|
||||||
row.classList.toggle('selected', cb.checked);
|
|
||||||
});
|
|
||||||
updateDeleteState();
|
|
||||||
});
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
var cb = row.querySelector('.row-check');
|
|
||||||
cb.addEventListener('change', function () {
|
|
||||||
row.classList.toggle('selected', cb.checked);
|
|
||||||
if (!cb.checked && selectAll) selectAll.checked = false;
|
|
||||||
updateDeleteState();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateDeleteState() {
|
|
||||||
if (!btnDelete) return;
|
|
||||||
var n = rows.filter(function (r) { return r.querySelector('.row-check').checked; }).length;
|
|
||||||
btnDelete.disabled = n === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
btnDelete && btnDelete.addEventListener('click', function () {
|
|
||||||
var ids = rows.filter(function (r) { return r.querySelector('.row-check').checked; })
|
|
||||||
.map(function (r) { return r.dataset.id; });
|
|
||||||
if (!ids.length) return;
|
|
||||||
if (!confirm('确定要删除选中的 ' + ids.length + ' 封邮件吗?')) return;
|
|
||||||
var done = 0;
|
|
||||||
ids.forEach(function (id) {
|
|
||||||
fetch('/mail/delete/' + id, { method: 'POST', body: new FormData() })
|
|
||||||
.then(function () { if (++done === ids.length) window.location.reload(); })
|
|
||||||
.catch(function () { if (++done === ids.length) window.location.reload(); });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var btnRefresh = document.getElementById('btn-refresh');
|
|
||||||
btnRefresh && btnRefresh.addEventListener('click', function () { window.location.reload(); });
|
|
||||||
|
|
||||||
searchInput && searchInput.addEventListener('input', function () {
|
|
||||||
var q = searchInput.value.trim().toLowerCase();
|
|
||||||
rows.forEach(function (row) {
|
|
||||||
var text = row.textContent.toLowerCase();
|
|
||||||
row.style.display = (!q || text.indexOf(q) !== -1) ? '' : 'none';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
||||||
Reference in New Issue
Block a user