件上按 ×:刚加的行直接拿掉,原有的行挂记号 —— 且记号要看得见(W05 1.4.2)

用户:「编辑点击再加一行后,点击旁边的叉没有反应」。两层病:
- 件:E04 那套 jc-row-gone / jc-row-new 的样式挂在它自己的外壳类下,W05 按目标件重做后
  表是 table.on,一条都没跟过来 —— × 按了类是切了、屏上没动静。补四条。
- ui-kit:刚「加一行」加出来的行按 × 也只是挂记号 —— 它从没存在过,挂记号再保存送出去的是
  一条「撤掉一行草稿里没有的行」,服务端只能回认不出。抽成 dropRow:jc-row-new 的直接移除,
  原有的行挂记号、再按摘掉;jsdom 钉两条。
浏览器在用户在跑那一单上实证:加行 1→2,× 后 1;原有行 × 一次挂记号、两次摘掉;取消回 1。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FJcX8A6TWp4GRs41TYryEh
This commit is contained in:
xcs
2026-08-27 13:42:35 +08:00
co-authored by Claude Fable 5
parent fa27cef60e
commit ffa1ef1076
4 changed files with 55 additions and 3 deletions
@@ -20,7 +20,7 @@
*/
// @vitest-environment jsdom
import { describe, expect, it } from 'vitest';
import { collect, fileRefOf, unanswered } from '../src/ViewContainer.tsx';
import { collect, dropRow, fileRefOf, unanswered } from '../src/ViewContainer.tsx';
/** 三行,每行一个手写三选一(照 A2/A4 现存的 `.jc-radiogrp` 结构,input 距 <tr> 四层) */
function radioTable(): Document {
@@ -194,3 +194,31 @@ describe('fileRefOf —— data-file 解析', () => {
expect(fileRefOf('不是地址/CT-1')).toBeUndefined();
});
});
/**
* 按 × 的两种下场(2026-08-27 用户在 W05 上:「编辑点击再加一行后,点击旁边的叉没有反应」)。
* 类是切了、件里没那条样式是件的事;这里钉的是行为:刚加的行按 × 直接没了,原有的行挂记号、再按摘掉。
*/
describe('dropRow:刚加的行直接拿掉,原有的行挂记号', () => {
const table = () => {
const doc = document.implementation.createHTMLDocument('');
doc.body.innerHTML = '<table><tbody data-edit="a.b"><tr id="old"><td>x</td></tr><tr id="fresh" class="jc-row-new"><td></td></tr></tbody></table>';
return doc;
};
it('jc-row-new 的行 → 从表里移除(它从没存在过,挂记号再保存只会送一条认不出的撤行)', () => {
const doc = table();
const fresh = doc.getElementById('fresh')!;
expect(dropRow(fresh)).toBe('removed');
expect(doc.getElementById('fresh')).toBeNull();
expect(doc.querySelectorAll('tbody tr')).toHaveLength(1);
});
it('原有的行 → 第一次挂 jc-row-gone,第二次摘掉;行本身一直在(人看得见、有得后悔)', () => {
const doc = table();
const old = doc.getElementById('old')!;
expect(dropRow(old)).toBe('marked');
expect(old.classList.contains('jc-row-gone')).toBe(true);
expect(dropRow(old)).toBe('unmarked');
expect(old.classList.contains('jc-row-gone')).toBe(false);
expect(doc.getElementById('old')).not.toBeNull();
});
});
+19 -1
View File
@@ -277,6 +277,22 @@ function collectGone(doc: Document, address: string): Array<Record<string, strin
});
}
/**
* **按下某一行的 ×**:两种行两种下场。
* · 本轮「加一行」加出来的(`jc-row-new`)—— 它从没存在过,直接拿掉;挂个记号再保存,
* 送出去的是一条「撤掉一行草稿里没有的行」,服务端只能回「认不出」,人看着像没删成;
* · 原本就有的行 —— 挂记号(`jc-row-gone`),不当场抹掉:人得看得见自己删了哪一行,
* 也才有得后悔(「取消」把记号摘了就回来了);再按一次 × 记号摘掉。
* 抽成函数是为了钉测:2026-08-27 用户在 W05 上按 × 「没有反应」—— 类是切了,件里没有那条样式。
*/
export function dropRow(row: HTMLElement): 'removed' | 'marked' | 'unmarked' {
if (row.classList.contains('jc-row-new')) {
row.remove();
return 'removed';
}
return row.classList.toggle('jc-row-gone') ? 'marked' : 'unmarked';
}
/**
* **在表尾添一行空的** —— 照末行的样子克隆,值清空。
*
@@ -493,7 +509,9 @@ export function ViewContainer({ html, title = '活动视图', editable = false,
* 人得看得见自己删了哪一行,也才有得后悔(「取消」把记号摘了就回来了)。
*/
if (del !== undefined) {
target?.closest?.('tr')?.classList.toggle('jc-row-gone');
const row = target?.closest?.('tr') ?? null;
if (row !== null) dropRow(row);
measureRef.current();
return;
}
if (add !== undefined) {