refactor(frontend): replace toast system with zibll notyf
This commit is contained in:
1 parent
fb11a7ed0c
commit
86614c4905
33 files changed
+603
-802
No files matched your search
+8
-126
@@ -3,7 +3,6 @@
|
||||
*
|
||||
* Unified core primitives for the entire frontend:
|
||||
* aksrt.tbquire(deps, cb) — lazy script/CSS loader
|
||||
* aksrt.notyf(msg, opts) — unified toast (same-ID update)
|
||||
* aksrt.confirm(msg, opts) — i18n confirm dialog
|
||||
* aksrt.scrollTopTo(target, off) — smart scroll with header offset
|
||||
* aksrt.loading(el, show) — element-level loading overlay
|
||||
@@ -93,123 +92,6 @@
|
||||
return p;
|
||||
};
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// §10.10 — notyf: unified toast with same-ID update
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
var _notyfContainer = null;
|
||||
var _notyfMap = {};
|
||||
var NOTYF_DURATION = 5000;
|
||||
|
||||
function getNotyfContainer() {
|
||||
if (_notyfContainer && _notyfContainer.parentNode) return _notyfContainer;
|
||||
_notyfContainer = document.createElement('div');
|
||||
_notyfContainer.className = 'aksrt-notyf';
|
||||
_notyfContainer.setAttribute('role', 'alert');
|
||||
_notyfContainer.setAttribute('aria-live', 'polite');
|
||||
document.body.appendChild(_notyfContainer);
|
||||
return _notyfContainer;
|
||||
}
|
||||
|
||||
function createNotyfItem(msg, opts) {
|
||||
var el = document.createElement('div');
|
||||
el.className = 'aksrt-notyf__item aksrt-notyf--' + (opts.type || 'info');
|
||||
if (opts.type === 'load') el.classList.add('aksrt-notyf--loading');
|
||||
|
||||
var iconMap = {
|
||||
success: '<i class="fas fa-check-circle"></i>',
|
||||
danger: '<i class="fas fa-exclamation-circle"></i>',
|
||||
error: '<i class="fas fa-exclamation-circle"></i>',
|
||||
warning: '<i class="fas fa-exclamation-triangle"></i>',
|
||||
load: '<i class="fas fa-spinner fa-spin"></i>',
|
||||
info: '<i class="fas fa-info-circle"></i>'
|
||||
};
|
||||
|
||||
el.innerHTML =
|
||||
'<span class="aksrt-notyf__icon">' + (iconMap[opts.type] || iconMap.info) + '</span>' +
|
||||
'<span class="aksrt-notyf__text">' + escapeHtml(msg) + '</span>' +
|
||||
'<button type="button" class="aksrt-notyf__close" aria-label="Close">×</button>';
|
||||
|
||||
el.querySelector('.aksrt-notyf__close').addEventListener('click', function () {
|
||||
removeNotyf(el, opts.id);
|
||||
});
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
function removeNotyf(el, id) {
|
||||
el.classList.add('aksrt-notyf--out');
|
||||
setTimeout(function () {
|
||||
if (el.parentNode) el.parentNode.removeChild(el);
|
||||
}, 300);
|
||||
if (id && _notyfMap[id]) {
|
||||
clearTimeout(_notyfMap[id].timer);
|
||||
delete _notyfMap[id];
|
||||
}
|
||||
}
|
||||
|
||||
aksrt.notyf = function (msg, opts) {
|
||||
if (typeof opts === 'string') opts = { type: opts };
|
||||
opts = opts || {};
|
||||
var type = opts.type || 'info';
|
||||
var duration = type === 'load' ? 0 : (opts.duration || NOTYF_DURATION);
|
||||
var id = opts.id || null;
|
||||
|
||||
var container = getNotyfContainer();
|
||||
|
||||
if (id && _notyfMap[id]) {
|
||||
var existing = _notyfMap[id];
|
||||
clearTimeout(existing.timer);
|
||||
existing.el.className = 'aksrt-notyf__item aksrt-notyf--' + type;
|
||||
existing.el.querySelector('.aksrt-notyf__text').textContent = msg;
|
||||
var iconSpan = existing.el.querySelector('.aksrt-notyf__icon');
|
||||
var iconMap2 = {
|
||||
success: '<i class="fas fa-check-circle"></i>',
|
||||
danger: '<i class="fas fa-exclamation-circle"></i>',
|
||||
error: '<i class="fas fa-exclamation-circle"></i>',
|
||||
warning: '<i class="fas fa-exclamation-triangle"></i>',
|
||||
load: '<i class="fas fa-spinner fa-spin"></i>',
|
||||
info: '<i class="fas fa-info-circle"></i>'
|
||||
};
|
||||
iconSpan.innerHTML = iconMap2[type] || iconMap2.info;
|
||||
if (duration > 0) {
|
||||
existing.timer = setTimeout(function () { removeNotyf(existing.el, id); }, duration);
|
||||
}
|
||||
return existing.el;
|
||||
}
|
||||
|
||||
var el = createNotyfItem(msg, { type: type, id: id });
|
||||
container.appendChild(el);
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
el.classList.add('aksrt-notyf--in');
|
||||
});
|
||||
|
||||
var timer = null;
|
||||
if (duration > 0) {
|
||||
timer = setTimeout(function () { removeNotyf(el, id); }, duration);
|
||||
}
|
||||
|
||||
if (id) {
|
||||
_notyfMap[id] = { el: el, timer: timer };
|
||||
}
|
||||
|
||||
return el;
|
||||
};
|
||||
|
||||
aksrt.notyf.close = function (id) {
|
||||
if (_notyfMap[id]) removeNotyf(_notyfMap[id].el, id);
|
||||
};
|
||||
|
||||
// Backward compat: wire window.aksrtToast to notyf
|
||||
window.aksrtToast = function (msg, type) {
|
||||
aksrt.notyf(msg, { type: type || 'info', duration: 2200 });
|
||||
};
|
||||
// Alias used by several modules that call aksrt.toast(...)
|
||||
aksrt.toast = function (msg, type) {
|
||||
return aksrt.notyf(msg, typeof type === 'string' ? { type: type, duration: 2200 } : (type || { duration: 2200 }));
|
||||
};
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// §10.10 — confirm: i18n confirm dialog + [data-confirm]
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
@@ -551,7 +433,7 @@
|
||||
if (action === 'like' || action === 'favorite') {
|
||||
try {
|
||||
if (localStorage.getItem(storageKey) && !btn.classList.contains('is-active')) {
|
||||
aksrt.notyf(__('already_done', '已操作'), 'warning');
|
||||
notyf(__('already_done', '已操作'), 'warning');
|
||||
return;
|
||||
}
|
||||
} catch (ex) { /* storage unavailable */ }
|
||||
@@ -562,7 +444,7 @@
|
||||
var ajaxUrl = (window.aksrtData && aksrtData.ajaxUrl) || '/wp-admin/admin-ajax.php';
|
||||
if (!(window.aksrtData && aksrtData.nonce)) {
|
||||
btn.classList.remove('is-loading');
|
||||
aksrt.notyf(__('action_failed', '操作失败'), 'danger');
|
||||
notyf(__('action_failed', '操作失败'), 'danger');
|
||||
return;
|
||||
}
|
||||
var params = new URLSearchParams();
|
||||
@@ -602,19 +484,19 @@
|
||||
} catch (ex) { /* */ }
|
||||
|
||||
if (json.data && json.data.message) {
|
||||
aksrt.notyf(json.data.message, 'success');
|
||||
notyf(json.data.message, 'success');
|
||||
}
|
||||
|
||||
if (json.data && json.data.goto) {
|
||||
window.location.href = json.data.goto;
|
||||
}
|
||||
} else {
|
||||
aksrt.notyf((json.data && json.data.message) || __('action_failed', '操作失败'), 'danger');
|
||||
notyf((json.data && json.data.message) || __('action_failed', '操作失败'), 'danger');
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
btn.classList.remove('is-loading');
|
||||
aksrt.notyf(err.message || __('network_error', '网络错误'), 'danger');
|
||||
notyf(err.message || __('network_error', '网络错误'), 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -651,7 +533,7 @@
|
||||
kind: 'generic',
|
||||
});
|
||||
} else if (json.data && json.data.message) {
|
||||
aksrt.notyf(json.data.message, 'success');
|
||||
notyf(json.data.message, 'success');
|
||||
}
|
||||
if (json.data && json.data.goto) {
|
||||
window.location.href = json.data.goto;
|
||||
@@ -660,12 +542,12 @@
|
||||
window.location.reload();
|
||||
}
|
||||
} else {
|
||||
aksrt.notyf((json.data && json.data.message) || __('action_failed', '操作失败'), 'danger');
|
||||
notyf((json.data && json.data.message) || __('action_failed', '操作失败'), 'danger');
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
btn.classList.remove('is-loading');
|
||||
aksrt.notyf(err.message || __('network_error', '网络错误'), 'danger');
|
||||
notyf(err.message || __('network_error', '网络错误'), 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user