diff --git a/resources/js/front.js b/resources/js/front.js new file mode 100644 index 0000000..69f6425 --- /dev/null +++ b/resources/js/front.js @@ -0,0 +1,133 @@ +// 前台普通页面交互入口,集中管理确认弹窗、聊天室弹窗和说明页导航高亮。 + +let frontControlsBound = false; + +/** + * 读取元素上声明的确认文案,并在用户取消时拦截默认行为。 + * + * @param {Event} event + * @param {Element} element + * @param {string} attribute + * @returns {boolean} + */ +function confirmBeforeAction(event, element, attribute) { + const message = element.getAttribute(attribute); + if (!message || window.confirm(message)) { + return true; + } + + event.preventDefault(); + return false; +} + +/** + * 打开独立聊天室窗口,并尽量铺满当前可用屏幕。 + * + * @param {string} url + * @param {string} roomName + * @returns {void} + */ +function openChatRoomWindow(url, roomName) { + const chatWindow = window.open( + url, + `chatroom_${roomName}`, + "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes", + ); + + if (!chatWindow) { + return; + } + + chatWindow.moveTo(0, 0); + chatWindow.resizeTo(window.screen.availWidth, window.screen.availHeight); + chatWindow.focus(); +} + +/** + * 绑定说明页右侧导航的可视区高亮。 + * + * @returns {void} + */ +function bindGuideNavigation() { + const aside = document.getElementById("guide-aside"); + const nav = document.getElementById("guide-nav"); + if (!aside || !nav) { + return; + } + + const checkWidth = () => { + aside.style.display = window.innerWidth >= 1024 ? "block" : "none"; + }; + checkWidth(); + window.addEventListener("resize", checkWidth); + + const links = Array.from(nav.querySelectorAll("a")); + const sections = links + .map((link) => { + const id = link.getAttribute("href")?.slice(1); + const element = id ? document.getElementById(id) : null; + + return element ? { element, link } : null; + }) + .filter(Boolean); + + const onScroll = () => { + let current = sections[0]; + sections.forEach((section) => { + if (section.element.getBoundingClientRect().top <= 120) { + current = section; + } + }); + + links.forEach((link) => link.classList.remove("active")); + current?.link.classList.add("active"); + }; + + window.addEventListener("scroll", onScroll, { passive: true }); + onScroll(); +} + +/** + * 绑定前台普通页面的轻量事件代理。 + * + * @returns {void} + */ +function bindFrontControls() { + if (frontControlsBound || typeof document === "undefined") { + return; + } + + frontControlsBound = true; + + document.addEventListener("click", (event) => { + if (!(event.target instanceof Element)) { + return; + } + + const submitButton = event.target.closest("[data-front-submit-confirm]"); + if (submitButton && !confirmBeforeAction(event, submitButton, "data-front-submit-confirm")) { + return; + } + + const roomLink = event.target.closest("[data-chat-room-window-url]"); + if (roomLink) { + event.preventDefault(); + openChatRoomWindow( + roomLink.getAttribute("data-chat-room-window-url") ?? "", + roomLink.getAttribute("data-chat-room-window-name") ?? "room", + ); + } + }); + + document.addEventListener("submit", (event) => { + if (!(event.target instanceof HTMLFormElement)) { + return; + } + + confirmBeforeAction(event, event.target, "data-front-confirm"); + }); + + bindGuideNavigation(); +} + +bindFrontControls(); diff --git a/resources/views/guestbook/index.blade.php b/resources/views/guestbook/index.blade.php index 5e42b89..d3f1a88 100644 --- a/resources/views/guestbook/index.blade.php +++ b/resources/views/guestbook/index.blade.php @@ -204,7 +204,7 @@ {{ \Carbon\Carbon::parse($msg->post_time)->diffForHumans() }} @if ($isFromMe || $isToMe || (Auth::check() && Auth::user()->user_level >= 15))