fix: align market selection checkboxes

This commit is contained in:
admin123 2026-04-24 22:10:16 +08:00
parent 7da1bcf255
commit fe60253cd3
3 changed files with 121 additions and 34 deletions

View File

@ -431,7 +431,7 @@ function readDivGridAuthorIds(root: ParentNode): string[] | null {
) ?? null ) ?? null
: null; : null;
const authorColumn = authorSection const authorColumn = authorSection
? getDirectContentColumns(authorSection)[0] ?? null ? getNativeAuthorColumn(authorSection)
: null; : null;
if (!authorColumn) { if (!authorColumn) {
return null; return null;
@ -497,7 +497,7 @@ function syncDivGridRoot(root: HTMLElement): MarketTableDom | null {
type: "body" type: "body"
}); });
const authorColumn = getDirectContentColumns(authorSection)[0] ?? null; const authorColumn = getNativeAuthorColumn(authorSection);
const actionColumn = getActionColumn(rightSection); const actionColumn = getActionColumn(rightSection);
if (!authorColumn || !actionColumn) { if (!authorColumn || !actionColumn) {
@ -752,7 +752,11 @@ function ensureDivHeaderCell(
nextCell.textContent = label; nextCell.textContent = label;
applyColumnWidth(nextCell, field); applyColumnWidth(nextCell, field);
applyPluginHeaderCellStyles(nextCell); applyPluginHeaderCellStyles(nextCell);
if (field === SELECTION_COLUMN_KEY) {
container.insertBefore(nextCell, templateCell);
} else {
container.appendChild(nextCell); container.appendChild(nextCell);
}
return nextCell; return nextCell;
} }
@ -774,7 +778,11 @@ function ensureDivBodyColumn(
nextColumn.dataset.marketColumnGroup = field; nextColumn.dataset.marketColumnGroup = field;
applyColumnWidth(nextColumn, field); applyColumnWidth(nextColumn, field);
syncDivColumnCells(nextColumn, templateColumn, field, rowCount); syncDivColumnCells(nextColumn, templateColumn, field, rowCount);
if (field === SELECTION_COLUMN_KEY) {
container.insertBefore(nextColumn, templateColumn);
} else {
container.appendChild(nextColumn); container.appendChild(nextColumn);
}
return nextColumn; return nextColumn;
} }
@ -802,7 +810,9 @@ function syncDivColumnCells(
templateCells[index] ?? templateCells[templateCells.length - 1] ?? null; templateCells[index] ?? templateCells[templateCells.length - 1] ?? null;
const nextCell = const nextCell =
field === SELECTION_COLUMN_KEY field === SELECTION_COLUMN_KEY
? createBareContentCell(column.ownerDocument) ? templateCell
? createSelectionContentCell(templateCell)
: createBareContentCell(column.ownerDocument)
: templateCell : templateCell
? cloneElementShallow(templateCell) ? cloneElementShallow(templateCell)
: createBareContentCell(column.ownerDocument); : createBareContentCell(column.ownerDocument);
@ -1106,6 +1116,21 @@ function getActionColumn(bodySection: HTMLElement): HTMLElement | null {
return columns[columns.length - 1] ?? null; return columns[columns.length - 1] ?? null;
} }
function getNativeAuthorColumn(authorSection: HTMLElement): HTMLElement | null {
return (
getDirectContentColumns(authorSection).find(
(column) =>
!column.dataset.marketColumnGroup &&
getDirectContentCells(column).some(
(cell) =>
cell.querySelector("a") ||
cell.querySelector(".author-nickname") ||
Boolean(cell.dataset.authorId)
)
) ?? null
);
}
function getDirectHeaderCells(section: Element): HTMLElement[] { function getDirectHeaderCells(section: Element): HTMLElement[] {
return Array.from(section.querySelectorAll(".header-cell")).filter( return Array.from(section.querySelectorAll(".header-cell")).filter(
(cell): cell is HTMLElement => (cell): cell is HTMLElement =>
@ -1162,6 +1187,13 @@ function createBareContentCell(document: Document): HTMLElement {
return cell; return cell;
} }
function createSelectionContentCell(templateCell: HTMLElement): HTMLElement {
const cell = cloneElementShallow(templateCell);
cell.removeAttribute("data-testid");
cell.removeAttribute("data-author-id");
return cell;
}
function extractAuthorId(authorCell: HTMLElement): string { function extractAuthorId(authorCell: HTMLElement): string {
const explicitAuthorId = authorCell.dataset.authorId; const explicitAuthorId = authorCell.dataset.authorId;
if (explicitAuthorId) { if (explicitAuthorId) {

View File

@ -2682,9 +2682,7 @@ function installPaginationHarness(
} }
const renderPage = () => { const renderPage = () => {
const authorColumn = document.querySelector( const authorColumn = readAuthorContentColumn();
'[data-testid="author-section"] .content-column'
) as HTMLElement | null;
const middleColumn = document.querySelector( const middleColumn = document.querySelector(
'.middle-columns .content-column' '.middle-columns .content-column'
) as HTMLElement | null; ) as HTMLElement | null;
@ -2777,9 +2775,7 @@ function installAsyncPaginationHarness(
}; };
const renderPage = () => { const renderPage = () => {
const authorColumn = document.querySelector( const authorColumn = readAuthorContentColumn();
'[data-testid="author-section"] .content-column'
) as HTMLElement | null;
const middleColumn = document.querySelector( const middleColumn = document.querySelector(
'.middle-columns .content-column' '.middle-columns .content-column'
) as HTMLElement | null; ) as HTMLElement | null;
@ -2883,9 +2879,7 @@ function installLaggyPaginationHarness(
}; };
const renderPage = () => { const renderPage = () => {
const authorColumn = document.querySelector( const authorColumn = readAuthorContentColumn();
'[data-testid="author-section"] .content-column'
) as HTMLElement | null;
const middleColumn = document.querySelector( const middleColumn = document.querySelector(
'.middle-columns .content-column' '.middle-columns .content-column'
) as HTMLElement | null; ) as HTMLElement | null;
@ -2940,9 +2934,7 @@ function installLaggyPaginationHarness(
pageIndex += 1; pageIndex += 1;
updatePaginationState(pageIndex); updatePaginationState(pageIndex);
const authorColumn = document.querySelector( const authorColumn = readAuthorContentColumn();
'[data-testid="author-section"] .content-column'
) as HTMLElement | null;
const middleColumn = document.querySelector( const middleColumn = document.querySelector(
'.middle-columns .content-column' '.middle-columns .content-column'
) as HTMLElement | null; ) as HTMLElement | null;
@ -3014,9 +3006,7 @@ function installProgressivePaginationHarness(
price21To60s: string; price21To60s: string;
}> }>
) => { ) => {
const authorColumn = document.querySelector( const authorColumn = readAuthorContentColumn();
'[data-testid="author-section"] .content-column'
) as HTMLElement | null;
const middleColumn = document.querySelector( const middleColumn = document.querySelector(
'.middle-columns .content-column' '.middle-columns .content-column'
) as HTMLElement | null; ) as HTMLElement | null;
@ -3118,9 +3108,7 @@ function installLazyFieldHydrationHarness(options: {
const rightColumns = document.querySelectorAll( const rightColumns = document.querySelectorAll(
'[data-testid="right-section"] > .content-column' '[data-testid="right-section"] > .content-column'
); );
const authorCells = Array.from( const authorCells = readAuthorContentCells();
document.querySelectorAll('[data-testid="author-section"] .content-column .content-cell')
) as HTMLElement[];
const middleCells = Array.from( const middleCells = Array.from(
document.querySelectorAll(".middle-columns .content-column .content-cell") document.querySelectorAll(".middle-columns .content-column .content-cell")
) as HTMLElement[]; ) as HTMLElement[];
@ -3288,11 +3276,7 @@ function installPagedLazyFieldHydrationHarness(options: {
const rightColumns = document.querySelectorAll( const rightColumns = document.querySelectorAll(
'[data-testid="right-section"] > .content-column' '[data-testid="right-section"] > .content-column'
); );
const authorCells = Array.from( const authorCells = readAuthorContentCells();
document.querySelectorAll(
'[data-testid="author-section"] .content-column .content-cell'
)
) as HTMLElement[];
const middleCells = Array.from( const middleCells = Array.from(
document.querySelectorAll(".middle-columns .content-column .content-cell") document.querySelectorAll(".middle-columns .content-column .content-cell")
) as HTMLElement[]; ) as HTMLElement[];
@ -3531,14 +3515,40 @@ function readRowOrder() {
} }
function readDivAuthorOrder() { function readDivAuthorOrder() {
const authorColumn = document.querySelector( const authorColumn = readAuthorContentColumn();
'[data-testid="author-section"] .content-column'
);
return readVisualCells(authorColumn).map( return readVisualCells(authorColumn).map(
(cell) => cell.querySelector("a")?.textContent?.trim() ?? "" (cell) => cell.querySelector("a")?.textContent?.trim() ?? ""
); );
} }
function readAuthorContentColumn(): HTMLElement | null {
const nativeColumns = Array.from(
document.querySelectorAll('[data-testid="author-section"] > .content-column')
).filter(
(column): column is HTMLElement =>
column instanceof HTMLElement && !column.dataset.marketColumnGroup
);
if (nativeColumns.length === 1) {
return nativeColumns[0];
}
return (
nativeColumns.find((column) =>
Boolean(
column.querySelector('a[href*="/author-homepage/"]') ||
column.querySelector(".author-nickname") ||
column.querySelector("[data-testid^='author-cell-']")
)
) ?? null
);
}
function readAuthorContentCells(): HTMLElement[] {
return Array.from(
readAuthorContentColumn()?.querySelectorAll(":scope > .content-cell") ?? []
).filter((cell): cell is HTMLElement => cell instanceof HTMLElement);
}
function readDivRightRowTexts(rowIndex: number) { function readDivRightRowTexts(rowIndex: number) {
return Array.from( return Array.from(
document.querySelectorAll('[data-testid="right-section"] > .content-column'), document.querySelectorAll('[data-testid="right-section"] > .content-column'),

View File

@ -307,6 +307,28 @@ describe("market-dom-sync", () => {
expect(readAuthorNames()).toEqual(["达人 A", "达人 B"]); expect(readAuthorNames()).toEqual(["达人 A", "达人 B"]);
}); });
test("inserts the selection column before the native author column", () => {
document.body.innerHTML = buildRealMarketGridFixture();
const table = syncMarketTable(document);
if (!table) {
throw new Error("Expected market table");
}
expect(readAuthorSectionColumnKeys()).toEqual(["selection", "author"]);
});
test("keeps the selection cells aligned to the native author row heights", () => {
document.body.innerHTML = buildRealMarketGridFixture();
const table = syncMarketTable(document);
if (!table) {
throw new Error("Expected market table");
}
expect(readSelectionCellHeights()).toEqual(["120px", "120px"]);
});
test("uses native-like alignment styles for plugin cells", () => { test("uses native-like alignment styles for plugin cells", () => {
document.body.innerHTML = buildRealMarketGridFixtureWithScopedAttributes(); document.body.innerHTML = buildRealMarketGridFixtureWithScopedAttributes();
@ -962,14 +984,37 @@ function readSelectionRowCheckboxCount() {
} }
function readAuthorNames() { function readAuthorNames() {
const authorColumn = document.querySelector( const authorColumn = Array.from(
'[data-testid="author-section"] .content-column' document.querySelectorAll('[data-testid="author-section"] > .content-column')
); ).find((column) => (column as HTMLElement).querySelector("a")) as Element | null;
return readVisualCells(authorColumn).map( return readVisualCells(authorColumn).map(
(cell) => cell.querySelector("a")?.textContent?.trim() ?? "" (cell) => cell.querySelector("a")?.textContent?.trim() ?? ""
); );
} }
function readAuthorSectionColumnKeys() {
return Array.from(
document.querySelectorAll('[data-testid="author-section"] > .content-column'),
(column) => {
const element = column as HTMLElement;
if (element.dataset.marketColumnGroup) {
return element.dataset.marketColumnGroup;
}
return element.querySelector("a") ? "author" : "unknown";
}
);
}
function readSelectionCellHeights() {
return Array.from(
document.querySelectorAll(
'[data-testid="author-section"] [data-market-column-group="selection"] > .content-cell'
),
(cell) => (cell as HTMLElement).style.height
);
}
function readAuthorRowHiddenStates() { function readAuthorRowHiddenStates() {
return Array.from( return Array.from(
document.querySelectorAll('[data-testid^="author-cell-"]'), document.querySelectorAll('[data-testid^="author-cell-"]'),