Files
mce/templates/MetaLab-2026/static/js/settings-favorites.js
Victor_Jay 2449a27eb5
Some checks failed
CI / Lint + Build (push) Has been cancelled
refactor: CSP nonce替代unsafe-inline, HSTS始终启用, router/api拆分, 管理后台+用户设置页拆分, DB健康降级, 时区配置, UID统一解析, CI接入
审计修复:
- CSP: unsafe-inline移除, nonce替代; unsafe-eval保留供Vditor使用
- HSTS: 始终启用(不再依赖release模式)
- Controller Exp: common.GetGinExp包装, 不再直接读context
- UID解析: common.ParseUIDParam统一, follow/admin controller改用

重构:
- router/api.go(198行)拆为7个域文件: auth/settings/posts/comments/reactions/social/studio
- 管理后台站点设置: 单页拆为4个子页(brand/security/registration/content)+子菜单
- 前台用户设置页: 1201行拆为6个独立模板+6个独立JS文件

新增:
- DB健康检测中间件(middleware/db_health.go): 5s ping+降级页面
- 时区配置: config.yaml server.timezone→time.Local初始化
- .gitea/workflows/ci.yml: strict模式CI流水线
2026-06-22 03:06:24 +08:00

109 lines
5.0 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';
<script nonce="{{.CSPNonce}}">
(function () {
'use strict';
var toastEl = document.getElementById('settingsToast');
var toastTimer = null;
function showSettingsToast(msg, isError) {
if (!toastEl) return;
clearTimeout(toastTimer);
toastEl.textContent = msg;
toastEl.className = 'settings-toast' + (isError ? ' error' : '');
void toastEl.offsetWidth;
toastEl.classList.add('show');
toastTimer = setTimeout(function () {
toastEl.classList.remove('show');
}, 5000);
}
// ===== 收藏夹 Tab =====
(function () {
var listEl = document.getElementById('favFolderList');
var createBtn = document.getElementById('createFolderBtn');
if (!listEl) return;
// escapeHtml / api 由 shared/utils.js 统一提供
function loadFolders() {
listEl.innerHTML = '<div class="energy-log-empty">加载中...</div>';
api('GET', '/api/folders')
.then(function (d) {
if (!d.success) {
listEl.innerHTML = '<div class="energy-log-empty">' + escapeHtml(d.message || '加载失败') + '</div>';
return;
}
if (!d.data || !d.data.folders || d.data.folders.length === 0) {
listEl.innerHTML = '<div class="energy-log-empty">暂无收藏夹</div>';
return;
}
var html = '';
d.data.folders.forEach(function (f) {
var isDefault = f.is_default ? ' (默认)' : '';
var pub = f.is_public ? '公开' : '私密';
html += '<div class="fav-folder-card">'
+ '<div class="fav-folder-info">'
+ '<span class="fav-folder-name">' + escapeHtml(f.name) + isDefault + '</span>'
+ '<span class="fav-folder-meta">' + (f.item_count || 0) + ' 篇文章 · ' + pub + '</span>'
+ '</div>'
+ '<div class="fav-folder-actions">'
+ (f.is_default ? '' : '<button class="fav-folder-del" data-id="' + f.id + '">删除</button>')
+ '</div>'
+ '</div>';
});
listEl.innerHTML = html;
listEl.querySelectorAll('.fav-folder-del').forEach(function (btn) {
btn.addEventListener('click', function () {
var id = btn.getAttribute('data-id');
showConfirm('确认', '确定要删除此收藏夹?其中的收藏内容也将被清除。').then(function(ok) {
if (!ok) return;
api('DELETE', '/api/folders/' + id)
.then(function (r) {
if (r.success) {
showSettingsToast('收藏夹已删除');
loadFolders();
} else {
showSettingsToast(r.message || '删除失败', true);
}
})
.catch(function () {
showSettingsToast('删除失败', true);
});
});
});
});
})
.catch(function () {
listEl.innerHTML = '<div class="energy-log-empty">加载失败,请刷新页面重试</div>';
});
}
if (createBtn) {
createBtn.addEventListener('click', function () {
showPrompt('请输入收藏夹名称最多50个字符').then(function(name) {
if (!name || !name.trim()) return;
if (name.trim().length > 50) {
showSettingsToast('收藏夹名称不能超过 50 个字符', true);
return;
}
api('POST', '/api/folders', { name: name.trim(), description: '', is_public: false })
.then(function (r) {
if (r.success) {
showSettingsToast('收藏夹已创建');
loadFolders();
} else {
showSettingsToast(r.message || '创建失败', true);
}
})
.catch(function () {
showSettingsToast('创建失败', true);
});
});
});
}
loadFolders();
})();
})();