253 lines
8.1 KiB
JavaScript
253 lines
8.1 KiB
JavaScript
(function () {
|
||
var root = document.querySelector("[data-login-pop]");
|
||
if (!root) return;
|
||
|
||
var form = root.querySelector("[data-login-form]");
|
||
var password = root.querySelector("[data-login-password]");
|
||
var toggle = root.querySelector("[data-login-toggle]");
|
||
var toggleIcon = root.querySelector("[data-login-toggle-icon]");
|
||
var title = root.querySelector("[data-login-title]");
|
||
var description = root.querySelector("[data-login-desc]");
|
||
var submitBtn = root.querySelector("[data-login-submit]") || (form && form.querySelector('button[type="submit"]'));
|
||
var previousOverflow = "";
|
||
var switchAccountMode = false;
|
||
|
||
function closeRegister() {
|
||
if (typeof window.closeRegisterPop === "function") {
|
||
window.closeRegisterPop();
|
||
return;
|
||
}
|
||
var register = document.querySelector("[data-register-pop]");
|
||
if (register) register.classList.remove("is-open");
|
||
}
|
||
|
||
function closeUserMenu() {
|
||
var menu = document.querySelector("[data-user-menu].is-open");
|
||
if (menu) {
|
||
menu.classList.remove("is-open");
|
||
var t = menu.querySelector("[data-user-menu-toggle]");
|
||
if (t) t.setAttribute("aria-expanded", "false");
|
||
}
|
||
}
|
||
|
||
function clearFieldError(name) {
|
||
var field = root.querySelector('[data-field="' + name + '"]');
|
||
var err = root.querySelector('[data-field-error="' + name + '"]');
|
||
if (field) field.classList.remove("is-error");
|
||
if (err) {
|
||
err.hidden = true;
|
||
var text = err.querySelector("[data-field-error-text]");
|
||
if (text) text.textContent = "";
|
||
}
|
||
}
|
||
|
||
function clearAllErrors() {
|
||
root.querySelectorAll("[data-field]").forEach(function (el) {
|
||
el.classList.remove("is-error");
|
||
});
|
||
root.querySelectorAll("[data-field-error]").forEach(function (err) {
|
||
err.hidden = true;
|
||
var text = err.querySelector("[data-field-error-text]");
|
||
if (text) text.textContent = "";
|
||
});
|
||
}
|
||
|
||
function setFieldError(name, message) {
|
||
var field = root.querySelector('[data-field="' + name + '"]');
|
||
var err = root.querySelector('[data-field-error="' + name + '"]');
|
||
if (field) field.classList.add("is-error");
|
||
if (err) {
|
||
err.hidden = false;
|
||
var text = err.querySelector("[data-field-error-text]");
|
||
if (text) text.textContent = message || "";
|
||
}
|
||
}
|
||
|
||
function isLen4to16(value) {
|
||
var len = String(value || "").length;
|
||
return len >= 4 && len <= 16;
|
||
}
|
||
|
||
function validateForm() {
|
||
clearAllErrors();
|
||
var fd = new FormData(form);
|
||
var account = String(fd.get("account") || "").trim();
|
||
var pwd = String(fd.get("password") || "");
|
||
var valid = true;
|
||
|
||
if (!account) {
|
||
setFieldError("account", "请输入账号");
|
||
valid = false;
|
||
} else if (
|
||
!(window.AuthAPI && AuthAPI.isValidLoginAccount
|
||
? AuthAPI.isValidLoginAccount(account)
|
||
: isLen4to16(account) || account.indexOf("@") >= 0)
|
||
) {
|
||
setFieldError("account", "账号需为 4–16 位,或合法邮箱");
|
||
valid = false;
|
||
}
|
||
|
||
if (!pwd) {
|
||
setFieldError("password", "请输入密码");
|
||
valid = false;
|
||
} else if (!isLen4to16(pwd)) {
|
||
setFieldError("password", "密码需为 4–16 位");
|
||
valid = false;
|
||
}
|
||
|
||
if (!valid) return null;
|
||
return { account: account, password: pwd };
|
||
}
|
||
|
||
function mapServerError(err) {
|
||
var tip = (err && err.message) || "登录失败,请稍后重试";
|
||
if (/账号|账户|用户|不存在|邮箱/.test(tip) && !/密码/.test(tip)) {
|
||
setFieldError("account", tip);
|
||
return;
|
||
}
|
||
setFieldError("password", tip);
|
||
}
|
||
|
||
function isMobile() {
|
||
return window.matchMedia && window.matchMedia("(max-width: 768px)").matches;
|
||
}
|
||
|
||
function open(input) {
|
||
var event = input && typeof input.preventDefault === "function" ? input : null;
|
||
var options = event ? {} : input || {};
|
||
if (isMobile() && !options.forcePopup) {
|
||
if (event) event.preventDefault();
|
||
window.location.href = "/login";
|
||
return;
|
||
}
|
||
if (event) event.preventDefault();
|
||
switchAccountMode = !!options.switchAccount;
|
||
closeRegister();
|
||
closeUserMenu();
|
||
clearAllErrors();
|
||
if (options.resetForm && form) form.reset();
|
||
if (password) password.setAttribute("type", "password");
|
||
if (toggle) toggle.setAttribute("aria-label", "显示密码");
|
||
if (toggleIcon) {
|
||
toggleIcon.setAttribute("src", "/static/images/eye.svg");
|
||
toggleIcon.setAttribute("data-src", "/static/images/eye.svg");
|
||
}
|
||
if (title) title.textContent = switchAccountMode ? "切换账号" : "登录黄果短剧";
|
||
if (description) {
|
||
description.textContent = switchAccountMode
|
||
? "请输入其他账号和密码完成切换"
|
||
: "登录后可收藏作品、解锁付费剧集并查看观看历史";
|
||
}
|
||
root.classList.add("is-open");
|
||
previousOverflow = document.body.style.overflow;
|
||
document.body.style.overflow = "hidden";
|
||
var first = root.querySelector(".login-pop__input");
|
||
if (first) {
|
||
window.setTimeout(function () {
|
||
first.focus();
|
||
}, 0);
|
||
}
|
||
}
|
||
|
||
function close() {
|
||
root.classList.remove("is-open");
|
||
document.body.style.overflow = previousOverflow;
|
||
clearAllErrors();
|
||
switchAccountMode = false;
|
||
}
|
||
|
||
window.openLoginPop = open;
|
||
window.openAccountSwitchLogin = function () {
|
||
open({ forcePopup: true, switchAccount: true, resetForm: true });
|
||
};
|
||
window.closeLoginPop = close;
|
||
|
||
document.addEventListener("click", function (event) {
|
||
var opener = event.target.closest("[data-login-open]");
|
||
if (opener) {
|
||
open(event);
|
||
return;
|
||
}
|
||
|
||
// PC:拦截站内 /login 链接,改为打开弹窗;H5 放行跳转登录页
|
||
var loginLink = event.target.closest('a[href="/login"], a[href="/login/"], a[href="#login"]');
|
||
if (loginLink && !isMobile()) {
|
||
open(event);
|
||
return;
|
||
}
|
||
|
||
if (!root.classList.contains("is-open")) return;
|
||
if (event.target.closest("[data-login-close]")) {
|
||
close();
|
||
}
|
||
});
|
||
|
||
if (toggle && password && toggleIcon) {
|
||
toggle.addEventListener("click", function () {
|
||
var show = password.getAttribute("type") === "password";
|
||
password.setAttribute("type", show ? "text" : "password");
|
||
toggleIcon.setAttribute("src", show ? "/static/images/eye-off.svg" : "/static/images/eye.svg");
|
||
toggle.setAttribute("aria-label", show ? "隐藏密码" : "显示密码");
|
||
});
|
||
}
|
||
|
||
function setSubmitting(loading) {
|
||
if (!submitBtn) return;
|
||
submitBtn.disabled = !!loading;
|
||
submitBtn.classList.toggle("is-loading", !!loading);
|
||
submitBtn.textContent = loading ? "登录中…" : "登录";
|
||
}
|
||
|
||
if (form) {
|
||
form.querySelectorAll("input").forEach(function (input) {
|
||
input.addEventListener("input", function () {
|
||
var name = input.getAttribute("name");
|
||
if (name) clearFieldError(name);
|
||
});
|
||
});
|
||
|
||
form.addEventListener("submit", function (event) {
|
||
event.preventDefault();
|
||
if (!window.AuthAPI || !window.HttpRequest) {
|
||
setFieldError("password", "认证脚本未加载,请刷新页面");
|
||
return;
|
||
}
|
||
if (submitBtn && submitBtn.classList.contains("is-loading")) return;
|
||
|
||
var payload = validateForm();
|
||
if (!payload) return;
|
||
|
||
setSubmitting(true);
|
||
AuthAPI.login(payload)
|
||
.then(function (res) {
|
||
AuthAPI.toast((res && res.tip) || "登录成功", "success");
|
||
window.setTimeout(function () {
|
||
close();
|
||
window.location.reload();
|
||
}, 400);
|
||
})
|
||
.catch(function (err) {
|
||
setSubmitting(false);
|
||
mapServerError(err);
|
||
AuthAPI.toast((err && err.message) || "登录失败", "error");
|
||
});
|
||
});
|
||
}
|
||
|
||
document.addEventListener("keydown", function (event) {
|
||
if (event.key === "Escape" && root.classList.contains("is-open")) {
|
||
close();
|
||
}
|
||
});
|
||
|
||
try {
|
||
var params = new URLSearchParams(window.location.search || "");
|
||
if (params.get("auth") === "login") {
|
||
params.delete("auth");
|
||
var qs = params.toString();
|
||
window.history.replaceState(null, "", window.location.pathname + (qs ? "?" + qs : "") + window.location.hash);
|
||
open();
|
||
}
|
||
} catch (e) {}
|
||
})();
|