日期框补上日历弹层:flatpickr 改为无条件加载
用户实测:筛选区日期框换成文本框后手机上没了日历弹层、不好操作;多 18KB gzip 可以接受。
- layout.html 里 flatpickr(js + css + l10n)与 datetime-input.js 都改为**无条件加载**,
不再用 {{if .Flatpickr}} 按页开关 —— 「按页开开关」正是 2026-10-09 日期框 bug 的根源
(只给 type=datetime-local 挂了控件,后来加的 type=date 没人管)。
- 顺手删掉 `Page.Flatpickr` 字段与三处 `p.Flatpickr = true`(开关没了就不可能再漏设)。
- 守卫 TestDateInputsGoThroughAttachAll 相应改成:钉住「layout 无条件引入 flatpickr +
datetime-input + attachAll」、并禁止再出现 {{if .Flatpickr}}。
实测(展开筛选面板后):390/320 下 /stats /map /places 的日历都在最上层(z-index 99999)、
完全在视口内、elementFromPoint 命中日历本身;打字 20260606 → 2026-06-06 不变。
回归:./scripts/verify.sh PASS=349 FAIL=0 SKIP=0;JS 单测 45/45;320/390/1440 溢出与改前一致。
This commit is contained in:
@@ -216,17 +216,21 @@ func TestDateInputsGoThroughAttachAll(t *testing.T) {
|
||||
t.Fatalf("读取 layout.html 失败: %v", err)
|
||||
}
|
||||
lay := string(layout)
|
||||
// flatpickr 那段是「按需加载」的,datetime-input.js 不能跟着一起被关进去
|
||||
if i := strings.Index(lay, "{{if .Flatpickr}}"); i >= 0 {
|
||||
if j := strings.Index(lay[i:], "{{end}}"); j > 0 {
|
||||
if strings.Contains(lay[i:i+j], "datetime-input.js") {
|
||||
t.Error("datetime-input.js 被关进 {{if .Flatpickr}} 了 —— 公共页不加载 flatpickr," +
|
||||
"筛选区的 <input type=date> 就没人改造成文本框,原生那个吞位的老毛病会原样回来")
|
||||
}
|
||||
// 日期控件与它的日历弹层必须**无条件**加载:筛选区在公共页上也有日期框,而
|
||||
// 「按页开开关」这种写法漏过一次(2026-10-09 的日期框 bug 就是只挂了 datetime-local)。
|
||||
for _, needle := range []string{
|
||||
"/static/vendor/flatpickr/flatpickr.min.js",
|
||||
"/static/vendor/flatpickr/flatpickr.min.css",
|
||||
"/static/js/datetime-input.js",
|
||||
"rondDatetime.attachAll(",
|
||||
} {
|
||||
if !strings.Contains(lay, needle) {
|
||||
t.Errorf("layout.html 里缺 %s —— 那一页的日期框会退回原生控件(没有日历弹层)", needle)
|
||||
}
|
||||
}
|
||||
if !strings.Contains(lay, "rondDatetime.attachAll(") {
|
||||
t.Error("layout.html 没有调用 attachAll —— 日期框不会在页面加载时被改造")
|
||||
if strings.Contains(lay, "{{if .Flatpickr}}") {
|
||||
t.Error("layout.html 里又出现了 {{if .Flatpickr}} 这种按页开关 —— 日期控件已改成无条件加载," +
|
||||
"开关一旦漏设,那一页的日期框就没有日历弹层(别再引入会漏的东西)")
|
||||
}
|
||||
|
||||
names, err := fs.Glob(tmplFS, "templates/*.html")
|
||||
|
||||
@@ -31,7 +31,6 @@ func (s *Server) editPage(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
p.HasMap = true
|
||||
p.Flatpickr = true
|
||||
q := r.URL.Query()
|
||||
d := EditData{Page: p, Query: strings.TrimSpace(q.Get("q")), SourceCounts: map[string]int{}}
|
||||
d.VisitQuery = strings.TrimSpace(q.Get("vq"))
|
||||
|
||||
@@ -48,7 +48,6 @@ func (s *Server) adminPhotosPage(w http.ResponseWriter, r *http.Request) {
|
||||
s.serverError(w, r, err)
|
||||
return
|
||||
}
|
||||
p.Flatpickr = true
|
||||
p.HasMap = true
|
||||
d := PhotoData{Page: p, GeocodeReady: s.cfg.GeocodeKey != ""}
|
||||
catNames := s.categoryLabels(r.Context())
|
||||
|
||||
@@ -283,7 +283,6 @@ func (s *Server) topicsAdminPage(w http.ResponseWriter, r *http.Request) {
|
||||
s.serverError(w, r, err)
|
||||
return
|
||||
}
|
||||
p.Flatpickr = true
|
||||
d := TopicAdminData{Page: p}
|
||||
d.Flash, d.Err = r.URL.Query().Get("ok"), r.URL.Query().Get("err")
|
||||
u := userFrom(ctx)
|
||||
|
||||
@@ -220,9 +220,9 @@
|
||||
<link rel="stylesheet" href="/static/vendor/markercluster/MarkerCluster.Default.css?v={{.AssetV}}">
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .Flatpickr}}
|
||||
{{/* 日期选择器的样式。**无条件加载**:筛选区(公共页)也有日期框,按页开关会被漏掉
|
||||
(见下面 datetime-input 那段的长注释)。 */}}
|
||||
<link rel="stylesheet" href="/static/vendor/flatpickr/flatpickr.min.css?v={{.AssetV}}">
|
||||
{{end}}
|
||||
<link rel="stylesheet" href="/static/css/app.css?v={{.AssetV}}">
|
||||
{{/* accent-base 是站长选的主色原值:暗色模式会用 color-mix 把它提亮,否则深色底上的链接会看不清(原来的深绿在深底上只有 3.3:1)。 */}}
|
||||
<style>:root{--accent:{{.Settings.AccentColor}};--accent-soft:{{.Settings.AccentColor}}1a;--accent-base:{{.Settings.AccentColor}}}</style>
|
||||
@@ -243,14 +243,15 @@
|
||||
{{if or (eq .Nav "map") (eq .Nav "topics")}}<script src="/static/vendor/markercluster/leaflet.markercluster.js?v={{.AssetV}}"></script>{{end}}
|
||||
<script src="/static/js/rond-map.js?v={{.AssetV}}"></script>
|
||||
{{end}}
|
||||
{{if .Flatpickr}}
|
||||
{{/* 日期选择器 + 手输引导。**无条件加载**(js+css+l10n 约 18KB gzip),两个理由:
|
||||
① 筛选区在公共页上也有日期框(/stats /places /timeline 的起止日期、/map 自己的),
|
||||
「按页开开关」这种写法已经被证明会漏 —— 2026-10-09 的日期框 bug 就是只给
|
||||
type=datetime-local 挂了控件,后来加的 type=date 没人管;
|
||||
② 原生控件本身不可靠:Chrome 的年段能吞 6 位数字,敲 20260606 会变成 202606/06
|
||||
且 el.value 为空(筛选条件静默丢掉)。
|
||||
datetime-input.js 必须在 flatpickr 之后、页面内联脚本之前。 */}}
|
||||
<script src="/static/vendor/flatpickr/flatpickr.min.js?v={{.AssetV}}"></script>
|
||||
<script src="/static/vendor/flatpickr/l10n/zh.js?v={{.AssetV}}"></script>
|
||||
{{end}}
|
||||
{{/* 日期输入的解析器与手输引导。**无条件引入**:公共页的筛选区也有 <input type=date>,
|
||||
那边不加载 flatpickr(省 60 多 KB),走纯输入引导 —— 关键是原生 date 自己也不可靠
|
||||
(Chrome 的年段能吞 6 位数字,敲 20260606 会变成 202606/06 且 value 为空)。
|
||||
必须在 flatpickr 之后、页面内联脚本之前。 */}}
|
||||
<script src="/static/js/datetime-input.js?v={{.AssetV}}"></script>
|
||||
<script>
|
||||
/* 每一页都把日期输入改造一次(见 datetime-input.js 顶部说明)。
|
||||
|
||||
@@ -73,9 +73,6 @@ type Page struct {
|
||||
// HasMap 决定是否加载 Leaflet,避免没有地图的页面白下载一份地图库。
|
||||
HasMap bool
|
||||
|
||||
// Flatpickr 决定是否加载日期时间选择器(目前只有数据编辑页在用)。
|
||||
Flatpickr bool
|
||||
|
||||
// HasTopics 表示该数据集有专题,导航里才露出「专题」入口。
|
||||
HasTopics bool
|
||||
|
||||
|
||||
Reference in New Issue
Block a user