117 lines
5.5 KiB
JavaScript
117 lines
5.5 KiB
JavaScript
/* ============================================================================
|
||||
|
|
通用「新建弹框」开关(v81)
|
|||
|
|
----------------------------------------------------------------------------
|
|||
|
|
用户原话(2026-10-22):
|
|||
|
|
「首页上的其他卡片也应该有这些基本功能。比如电影观影,它有一个"新增电影"的
|
|||
|
|
功能;如果是纪念日,就有一个"新增纪念日"。实际上,就是把原来模块里弹的那个框,
|
|||
|
|
现在拿到这边来。目的就是为了在首页上就能快速完成一定工作,而不用进到模块里面。」
|
|||
|
|
|
|||
|
|
v78 给「近期任务」写过一份 `task_add.js`(只能管那一张弹框)。这一批要把
|
|||
|
|
观影、纪念日也搬上来 ⇒ 三份几乎一样的脚本 = 三处迟早不同步。所以抽这一份**通用的**:
|
|||
|
|
每张弹框只需声明自己的「容器 id / 开按钮 / 关按钮」三个名字。
|
|||
|
|
|
|||
|
|
用法(在弹框模板里给容器加两个属性即可,不需要改 JS):
|
|||
|
|
<div class="cal-modal" id="mvAddCard"
|
|||
|
|
data-fb-modal="mvAddCard" ← 容器 id(= 触发器的 data-fb-modal-open 值)
|
|||
|
|
data-fb-modal-open="[data-mv-add-open]"
|
|||
|
|
data-fb-modal-close="[data-mv-add-close]"
|
|||
|
|
hidden>
|
|||
|
|
或者更省事:容器上加 `data-fb-add-modal`,触发器上加
|
|||
|
|
`data-fb-add-open="#<容器id>"`、`data-fb-add-close` —— 全站约定见下。
|
|||
|
|
|
|||
|
|
行为(与站内其它浮层一致,v78 那套原样保留):
|
|||
|
|
· 点触发器开、点 ✕/取消 关、点**遮罩**关、点面板内部**不**关、Esc 关;
|
|||
|
|
· Esc 时若 antd 的日期面板开着,**先让 antd 收自己的**(否则一次 Esc 关两层,用户懵);
|
|||
|
|
· 打开那一刻才升级日期控件 —— 弹框初始 `hidden`,antd 面板拿到 0 尺寸会定位到
|
|||
|
|
屏幕左上角(task_add.js 与 tasks/show.php 都为此专门 boot 过,同一条坑)。
|
|||
|
|
|
|||
|
|
⚠️ 全站加载,页面里没有带 `data-fb-add-modal` 的容器时**什么都不做**(几行判断)。
|
|||
|
|
⚠️ 幂等闸门 `window.__fbAddModalBound`:脚本可能被重复引入(AJAX 换正文、模板重复),
|
|||
|
|
不加会绑两遍 ⇒ 点一次开两次、关两次。
|
|||
|
|
⚠️ 为什么不用内联 script:内联脚本在 AJAX 换正文时**不会被重跑**(v42/v47 连着栽过)。
|
|||
|
|
============================================================================ */
|
|||
|
|
(function () {
|
|||
|
|
'use strict';
|
|||
|
|
if (window.__fbAddModalBound) { return; }
|
|||
|
|
window.__fbAddModalBound = true;
|
|||
|
|
|
|||
|
|
/* 容器:`data-fb-add-modal` 自带 id 也算(省去写两遍) */
|
|||
|
|
function containers() {
|
|||
|
|
return Array.prototype.slice.call(
|
|||
|
|
document.querySelectorAll('[data-fb-add-modal]'));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function antdOpen() {
|
|||
|
|
var d = document.querySelector('.ant-picker-dropdown');
|
|||
|
|
return !!(d && !d.classList.contains('ant-picker-dropdown-hidden'));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 打开时要做的"补动作":日期控件必须等可见之后再升级(hidden 时宽高为 0)。
|
|||
|
|
两步都要:先绑自建下拉(兜底),再挂 antd(正主);两个函数都自判幂等。 */
|
|||
|
|
function wake(c) {
|
|||
|
|
if (window.fbUpgradeRange) { window.fbUpgradeRange(); }
|
|||
|
|
if (window.fbBootAntd) { window.fbBootAntd(); }
|
|||
|
|
/* 焦点落到第一颗输入框:键盘用户不用先 Tab 一遍 */
|
|||
|
|
var f = c.querySelector('input:not([type=hidden]), textarea, select');
|
|||
|
|
if (f && !f.disabled) { try { f.focus(); } catch (e) {} }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function show(c, on) {
|
|||
|
|
if (!c) { return; }
|
|||
|
|
c.hidden = !on;
|
|||
|
|
/* 触发器的 aria-expanded 跟着走(有就更新,没有不报错) */
|
|||
|
|
var sel = c.getAttribute('data-fb-modal-open');
|
|||
|
|
if (sel) {
|
|||
|
|
Array.prototype.forEach.call(document.querySelectorAll(sel), function (b) {
|
|||
|
|
b.setAttribute('aria-expanded', on ? 'true' : 'false');
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
if (on) { wake(c); }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 由点击位置反推"该开/该关哪一张":
|
|||
|
|
· 触发器上写 `data-fb-add-open="#id"`(显式指定容器);
|
|||
|
|
· 关闭按钮/遮罩则就近找祖先里的 `[data-fb-add-modal]`。 */
|
|||
|
|
function targetFor(t) {
|
|||
|
|
if (t.closest('[data-fb-add-close]')) {
|
|||
|
|
return { c: t.closest('[data-fb-add-modal]'), on: false };
|
|||
|
|
}
|
|||
|
|
var opener = t.closest('[data-fb-add-open]');
|
|||
|
|
if (opener) {
|
|||
|
|
var sel = opener.getAttribute('data-fb-add-open') || '';
|
|||
|
|
var c = sel ? document.querySelector(sel) : null;
|
|||
|
|
return { c: c, on: true };
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
document.addEventListener('click', function (e) {
|
|||
|
|
var t = e.target;
|
|||
|
|
if (!t || !t.closest) { return; }
|
|||
|
|
var hit = targetFor(t);
|
|||
|
|
if (hit) {
|
|||
|
|
if (hit.c) { e.preventDefault(); }
|
|||
|
|
show(hit.c, hit.on);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
/* 点遮罩关、点面板内不关 —— 容器本身就是遮罩层,所以只认 === */
|
|||
|
|
if (t.hasAttribute && t.hasAttribute('data-fb-add-modal')) {
|
|||
|
|
show(t, false);
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
document.addEventListener('keydown', function (e) {
|
|||
|
|
if (e.key !== 'Escape') { return; }
|
|||
|
|
var open = containers().filter(function (c) { return !c.hidden; });
|
|||
|
|
if (!open.length) { return; }
|
|||
|
|
if (antdOpen()) { return; } // 让 antd 先收它自己的面板
|
|||
|
|
show(open[open.length - 1], false);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
/* 供其它脚本(提交成功后就地插入回包等)主动开合:
|
|||
|
|
window.fbAddModal.open('#id') / .close('#id') */
|
|||
|
|
window.fbAddModal = {
|
|||
|
|
open: function (sel) { show(document.querySelector(sel), true); },
|
|||
|
|
close: function (sel) { show(document.querySelector(sel), false); }
|
|||
|
|
};
|
|||
|
|
})();
|