diff --git a/assets/css/app.css b/assets/css/app.css index 776dc63..2eedbab 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -599,14 +599,19 @@ textarea.input { min-height: 76px; resize: vertical; } ⚠️ 用 visibility:hidden 而不是 display:none —— 保留元素占位高度, 否则升级完成的那一瞬表单会"跳"一下(高度从 0 变 40px)。 */ html.js .dt-input:not(.is-semi) .dt-native { visibility: hidden; } -/* 🔴 v35:native 升级态 —— 不再挂 Semi,原生控件**就是要显示**。 - 这条必须写在上面那条**之后**(同选择器强度下后者胜), - 否则"未 .is-semi → 藏原生"会把我们露出来的控件又藏回去。 */ -html.js .dt-input.is-native .dt-native { visibility: visible; } -html.js .dt-input.is-native::after { display: none; } /* 去掉占位骨架 */ -html.js .dt-range.is-native-range .dt-input, -html.js .dt-range.is-native-range > .dt-range-label { visibility: visible; } -html.js .dt-range.is-native-range::before { display: none; } /* 去掉范围占位骨架 */ +/* 🔴🔴 v36:`.is-native` 态下,原生控件**必须可见**。 + 用 `!important` 是**故意**的:v35 那次就是被 + `html.js .dt-input:not(.is-semi) .dt-native{visibility:hidden}` + (特异性 0,3,0,比我那条覆盖规则更强/更早)又藏回了 hidden —— + 用户看到"一片空白、点不到",而探针因为用错判据(offsetParent)还"全绿"两轮。 + ⇒ 这条用 `!important` 一次性钉死,别再让任何历史规则把它藏起来。 */ +html.js .dt-input.is-native .dt-native { visibility: visible !important; } +html.js .dt-input.is-native::after { display: none !important; } +html.js .dt-range.is-native-range .dt-input { visibility: visible !important; } +html.js .dt-range.is-native-range > .dt-range-label { visibility: visible !important; } +html.js .dt-range.is-native-range::before { display: none !important; } +html.js .dt-range.is-native-range > .dt-input, +html.js .dt-range.is-native-range > .field { display: flex !important; } /* ⚠️ v24 第 21 批 第 7 条:两端现在各自被 `.field` 包着,所以选择器要跟着下沉一层。 写成 `> .dt-input` 的话这条**永远不会命中** → 未升级时原生控件照旧可见, 与下面那块"占位骨架"叠在一起,会看到两套控件重影。 */ @@ -738,27 +743,11 @@ body[class] .semi-datepicker-day-inhover { background-color: color-mix(in srgb, } .dt-input .dt-colon { color: var(--muted); font-weight: 600; } -/* 🔴 v35:v35 起时间不再是「时:分:秒」三个下拉,而是**一个**原生 - ``(24 小时制、精确到秒、点了就选、无需确认按钮)。 - 三个下拉仍在 DOM 里(提交契约不变),但视觉上收起来。 */ -.dt-input .dt-merged { display: none !important; } -.dt-input .dt-time-input { - flex: 0 0 auto; - padding: 9px 10px; border: 1px solid var(--line); border-radius: var(--radius-s); - background: var(--surface); color: var(--ink); font: inherit; - font-variant-numeric: tabular-nums; cursor: pointer; - accent-color: var(--brand); -} -.dt-input .dt-time-input::-webkit-calendar-picker-indicator { cursor: pointer; opacity: .65; } -/* 范围里两端各占一行时,"日期 + 时间"两个框排在一起 */ +/* 🔴 v36:时间不再有"合成的时间框"(v35 试过 ``,已弃用)。 + `.dt-merged` / `.dt-time-input` 的规则一并删掉 —— 免得将来有人误以为 + 还有"被收起来的下拉"。用户要的形态就是**日期 + 时/分下拉**直接显示。 */ .dt-input.is-native-range { gap: 8px; } .dt-range.is-native-range { display: flex; flex-direction: column; gap: 10px; } -/* 🔴 v35:`.dt-range.is-semi-range > .dt-input { display:none }` 是 **Semi 时代** - "两端让位给那个一体化范围控件"的规则。v35 起两端**就是要显示**的, - 所以 native-range 必须把它覆盖回来 —— 否则端点被 display:none,用户又看不到。 */ -.dt-range.is-native-range > .dt-input, -.dt-range.is-native-range > .field { display: flex; } -.dt-range.is-native-range > .field { flex-direction: column; gap: 8px; } /* 「以哪个生日为准」的两块:被选中的那块描一圈,一眼看出填的是哪边 */ .bd-source { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 6px; } diff --git a/assets/js/app.js b/assets/js/app.js index be49500..988c9c0 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -1406,64 +1406,47 @@ 这里只是把两端的日期框**露出来**、并把原来的 时/分/秒 三个下拉 合成**一个**原生时间框(三个下拉仍留在 DOM 里,只是不单独显示)。 */ - /* 把某个端点原来的「日期 + 三个下拉」变成「日期框 + 一个时间框」。 - 值照旧写回那三个下拉(POST 契约),只是视觉上收成一个控件。 */ - function mergeTimeInputs(box) { + + /* 🔴🔴 v36:**不合成任何"时间框",直接把原生的「日期 + 时/分下拉」露出来**。 + 用户原话(第 2 次反馈,2026-10-09): + 「观影模块,开始时间和结束时间是空白的,无法选择,可以调整为, + 前面是日期,后面是时和分,只记录到时和分就行了。时和分,是下拉的。」 + + ⚠️ v35 那一版为什么用户看到的是**一片空白**(我的锅): + 当时只给范围**组**加了 `.is-native-range`,**没给两个端点 `.dt-input` + 加 `.is-native`** —— 于是 CSS 里 + `html.js .dt-input:not(.is-semi) .dt-native { visibility: hidden; }` + 照样命中 ⇒ 控件 `visibility:hidden`(**占着 48px 高度、但完全不可见、点不到**)。 + 🔴 更糟的是探针当时用 `offsetParent !== null` 判"可见" —— + 对 `visibility:hidden` 的元素它**仍然返回 true**,于是连续两轮都"通过"。 + ⇒ 判可见**必须看 computed visibility**(_fb_b34_dtrange.py 已改)。 + + ⇒ 本版走最笨但最稳的路:**不造新控件**,直接把原有的 日期 + 时/分 下拉显示出来。 */ + function revealEndpoint(box) { var native = box.querySelector('.dt-native'); if (!native) { return; } - var dateEl = native.querySelector('.dt-date'); - var hourEl = native.querySelector('.dt-hour'); - var minEl = native.querySelector('.dt-minute'); - var secEl = native.querySelector('.dt-second'); - if (!dateEl || !hourEl || !minEl) { return; } - var timeEl = document.createElement('input'); - timeEl.type = 'time'; - timeEl.className = 'dt-time-input'; - timeEl.step = secEl ? '1' : '60'; // 要秒的槽位精确到秒 - timeEl.setAttribute('aria-label', '时间(24 小时制)'); - function syncFromSelects() { - timeEl.value = (hourEl.value || '00') + ':' + (minEl.value || '00') - + (secEl ? ':' + (secEl.value || '00') : ''); + // ① 端点加 `.is-native`(压掉"未 .is-semi 就藏原生"那条规则) + box.classList.add('is-native'); + // ② 去掉"秒"那一档(用户只要到分);紧跟它的那个冒号一起收掉 + var secEl = native.querySelector('.dt-second'); + if (secEl) { + var prev = secEl.previousElementSibling; + if (prev && prev.classList && prev.classList.contains('dt-colon')) { prev.remove(); } + secEl.remove(); } - syncFromSelects(); - timeEl.addEventListener('change', function () { - var m = (timeEl.value || '').match(/^(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?$/); - if (!m) { return; } - hourEl.value = pad(+m[1]); - minEl.value = pad(+m[2]); - if (secEl) { secEl.value = pad(+(m[3] || 0)); } - }); - // 供"程序化改值时让时间框跟上"(如日程页点日历空白处预填) - box.__fbSyncTime = syncFromSelects; - // 插在日期框后面;三个下拉只留下标(提交用),视觉隐藏 - dateEl.parentNode.insertBefore(timeEl, dateEl.nextSibling); - if (secEl) { secEl.classList.add('dt-merged'); } - minEl.classList.add('dt-merged'); - hourEl.classList.add('dt-merged'); - // 原来把 时:分:秒 串起来的分隔符也一起收掉 - var nat = box.querySelector('.dt-native'); - Array.prototype.forEach.call(nat.querySelectorAll('.dt-colon, .dt-time'), function (n) { - n.classList.add('dt-merged'); - }); + // ③ 显示(inline 覆盖,避免再被任何 CSS 规则藏住 —— 这是 v35 的教训) + native.style.display = 'contents'; + native.style.visibility = 'visible'; + box.style.display = ''; + box.style.visibility = 'visible'; + box.classList.add('has-value'); } - mergeTimeInputs(a); - mergeTimeInputs(b); + revealEndpoint(a); + revealEndpoint(b); - // 两端各自**露出来**(不再藏)—— v35 的形态就是"两个 日期+时间 对" - a.style.display = ''; - b.style.display = ''; - var na = a.querySelector('.dt-native'), nb = b.querySelector('.dt-native'); - if (na) { na.style.display = 'contents'; } - if (nb) { nb.style.display = 'contents'; } - a.classList.add('has-value'); - if (readDT(b).trim() !== ' ') { b.classList.add('has-value'); } - - // 仅供 fbSetDT / fbUpgradeRange 的既有调用点使用(不再挂 Semi) - group.__fbRemount = function () { - if (a.__fbSyncTime) { a.__fbSyncTime(); } - if (b.__fbSyncTime) { b.__fbSyncTime(); } - }; + // 供 fbSetDT / fbUpgradeRange 的既有调用点使用(不再挂 Semi,无需同步) + group.__fbRemount = function () {}; /* ⚠️ 原来这里会隐藏"端点最外层的包装"(因为 Semi 范围控件顶替了两端)。 v35 起两端**就是要显示**的,所以不再隐藏任何东西 —— @@ -1485,51 +1468,25 @@ var native = box.querySelector('.dt-native'); if (!native) { return; } - /* 🔴 v35:单点时间控件同样**不再用 Semi**(图省事不再区分两条路径)—— - Semi 的 `dateTime` 面板同样没有可选的时间列(见 upgradeRange 里的实测)。 - 这里只把原来的 时/分/秒 三个下拉合成**一个原生时间框**, - 日期框照旧是原生 `type="date"`,两者都**直接显示**。 - 契约不变(*_date/_hour/_minute/_second 仍在 DOM 里提交)。 */ - if (!box.__fbMerged) { - box.__fbMerged = true; - var dateEl = native.querySelector('.dt-date'); - var hourEl = native.querySelector('.dt-hour'); - var minEl = native.querySelector('.dt-minute'); - var secEl = native.querySelector('.dt-second'); - if (dateEl && hourEl && minEl) { - var timeEl = document.createElement('input'); - timeEl.type = 'time'; - timeEl.className = 'dt-time-input'; - timeEl.step = secEl ? '1' : '60'; - timeEl.setAttribute('aria-label', '时间(24 小时制)'); - function syncFromSelects() { - timeEl.value = (hourEl.value || '00') + ':' + (minEl.value || '00') - + (secEl ? ':' + (secEl.value || '00') : ''); - } - syncFromSelects(); - timeEl.addEventListener('change', function () { - var m = (timeEl.value || '').match(/^(\d{1,2}):(\d{1,2})(?::(\d{1,2}))?$/); - if (!m) { return; } - hourEl.value = pad(+m[1]); - minEl.value = pad(+m[2]); - if (secEl) { secEl.value = pad(+(m[3] || 0)); } - }); - box.__fbSyncTime = syncFromSelects; - dateEl.parentNode.insertBefore(timeEl, dateEl.nextSibling); - if (secEl) { secEl.classList.add('dt-merged'); } - minEl.classList.add('dt-merged'); - hourEl.classList.add('dt-merged'); - Array.prototype.forEach.call(native.querySelectorAll('.dt-colon, .dt-time'), function (n) { - n.classList.add('dt-merged'); - }); + /* 🔴 v36:单点控件也**不合成时间框**了 —— 与范围那两端同一套做法 + (见上面 revealEndpoint 的说明)。直接把原生的「日期 + 时/分下拉」显示出来。 + ⚠️ 秒那一档按用户要求去掉("只记录到时和分就行了")。 */ + if (!box.__fbRevealed) { + box.__fbRevealed = true; + var secEl1 = native.querySelector('.dt-second'); + if (secEl1) { + var prev1 = secEl1.previousElementSibling; + if (prev1 && prev1.classList && prev1.classList.contains('dt-colon')) { prev1.remove(); } + secEl1.remove(); } } - // 直接露出原生(日期 + 时间) - native.style.display = 'contents'; + // 端点加 .is-native(压掉"未 .is-semi 就藏原生"的规则)+ 直接显示 box.classList.add('is-native'); box.classList.add('has-value'); - // 程序化改值时让时间框跟上 - box.__fbRemount = function () { if (box.__fbSyncTime) { box.__fbSyncTime(); } }; + native.style.display = 'contents'; + native.style.visibility = 'visible'; + box.style.visibility = 'visible'; + box.__fbRemount = function () {}; guardRequired(box); box.setAttribute('data-semi-done', '1'); } diff --git a/templates/movies/form.php b/templates/movies/form.php index 6af4c85..9ad7f9a 100644 --- a/templates/movies/form.php +++ b/templates/movies/form.php @@ -75,12 +75,11 @@ $selAttendees = array_map('intval', (array)old('attendees', $curAttendees)); = e($errors['title']) ?> - +
+ 要加照片请点上方「编辑」——「观影照片」在编辑页里一起传(可多选)。 +