130 lines
4.3 KiB
JavaScript
130 lines
4.3 KiB
JavaScript
(function () {
|
|
// ✅ 스크립트가 실수로 2번 로드돼도 바인딩 1번만
|
|
if (window.__ADMIN_UI_JS_BOUND__) return;
|
|
window.__ADMIN_UI_JS_BOUND__ = true;
|
|
|
|
// -----------------------
|
|
// click handlers
|
|
// -----------------------
|
|
document.addEventListener('click', (e) => {
|
|
const t = e.target;
|
|
|
|
// password toggle
|
|
if (t && t.matches('[data-toggle="password"]')) {
|
|
const pw = document.getElementById('password');
|
|
if (!pw) return;
|
|
|
|
const isPw = pw.type === 'password';
|
|
pw.type = isPw ? 'text' : 'password';
|
|
t.textContent = isPw ? '숨기기' : '보기';
|
|
return;
|
|
}
|
|
});
|
|
|
|
// -----------------------
|
|
// ✅ data-confirm (ONLY ONCE)
|
|
// - capture 단계에서 먼저 실행되어
|
|
// 취소 시 다른 submit 리스너(버튼 disable 등) 실행 안 됨
|
|
// -----------------------
|
|
document.addEventListener('submit', (e) => {
|
|
const form = e.target;
|
|
if (!(form instanceof HTMLFormElement)) return;
|
|
|
|
const raw = form.getAttribute('data-confirm');
|
|
if (!raw) return;
|
|
|
|
// 이미 confirm 통과한 submit이면 다시 confirm 금지
|
|
if (form.dataset.confirmed === '1') return;
|
|
|
|
// "\n" 문자, " " 엔티티 모두 줄바꿈 처리
|
|
const msg = String(raw)
|
|
.replace(/\\n/g, '\n')
|
|
.replace(/ /g, '\n');
|
|
|
|
if (!window.confirm(msg)) {
|
|
e.preventDefault();
|
|
e.stopImmediatePropagation();
|
|
return;
|
|
}
|
|
|
|
form.dataset.confirmed = '1';
|
|
// confirm 통과 -> 그대로 진행 (다른 submit 리스너 정상 실행)
|
|
}, true);
|
|
|
|
// -----------------------
|
|
// login submit UI (disable + text)
|
|
// -----------------------
|
|
// document.addEventListener('submit', (e) => {
|
|
// const form = e.target;
|
|
// if (!form || !form.matches('[data-form="login"]')) return;
|
|
//
|
|
// const btn = form.querySelector('[data-submit]');
|
|
// if (btn) {
|
|
// btn.disabled = true;
|
|
// btn.dataset.original = btn.textContent;
|
|
// btn.textContent = '처리 중...';
|
|
// }
|
|
// });
|
|
|
|
// -----------------------
|
|
// showMsg (toast)
|
|
// -----------------------
|
|
if (typeof window.showMsg !== 'function') {
|
|
function ensureWrap() {
|
|
let wrap = document.getElementById('a-toast-wrap');
|
|
if (!wrap) {
|
|
wrap = document.createElement('div');
|
|
wrap.id = 'a-toast-wrap';
|
|
wrap.className = 'a-toast-wrap';
|
|
document.body.appendChild(wrap);
|
|
}
|
|
return wrap;
|
|
}
|
|
|
|
window.showMsg = function (message, opt = {}) {
|
|
const type = opt.type || 'info'; // success | info | warn | danger
|
|
const title = opt.title || '';
|
|
|
|
const wrap = ensureWrap();
|
|
|
|
const toast = document.createElement('div');
|
|
toast.className = `a-toast a-toast--${type}`;
|
|
|
|
const t = document.createElement('div');
|
|
t.className = 'a-toast__title';
|
|
t.textContent = title || (type === 'success' ? '완료' : type === 'danger' ? '오류' : '안내');
|
|
|
|
const m = document.createElement('div');
|
|
m.className = 'a-toast__msg';
|
|
m.textContent = String(message || '');
|
|
|
|
toast.appendChild(t);
|
|
toast.appendChild(m);
|
|
wrap.appendChild(toast);
|
|
|
|
const ttl = Number(opt.ttl || 3000);
|
|
window.setTimeout(() => {
|
|
toast.style.opacity = '0';
|
|
toast.style.transform = 'translateY(-4px)';
|
|
toast.style.transition = 'all .15s ease';
|
|
window.setTimeout(() => toast.remove(), 180);
|
|
}, ttl);
|
|
|
|
toast.addEventListener('click', () => toast.remove());
|
|
|
|
return Promise.resolve();
|
|
};
|
|
}
|
|
|
|
// flash 자동 표시
|
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
const list = window.__adminFlash;
|
|
if (!Array.isArray(list) || list.length === 0) return;
|
|
|
|
for (const f of list) {
|
|
await window.showMsg(f.message, { type: f.type, title: f.title, ttl: 3200 });
|
|
}
|
|
window.__adminFlash = [];
|
|
});
|
|
})();
|