Fix patrol delete condition handling
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
function textOf(node) {
|
||||
return ((node && (node.innerText || node.textContent || '')) || '').replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
function isVisible(el) {
|
||||
if (!el || !el.getBoundingClientRect) return false;
|
||||
const rect = el.getBoundingClientRect();
|
||||
const style = window.getComputedStyle(el);
|
||||
return rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden';
|
||||
}
|
||||
|
||||
function clickElement(el) {
|
||||
el.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||
if (el.focus) el.focus();
|
||||
for (const eventName of ['pointerdown', 'mousedown', 'pointerup', 'mouseup']) {
|
||||
el.dispatchEvent(new MouseEvent(eventName, { bubbles: true, cancelable: true, view: window }));
|
||||
}
|
||||
el.click();
|
||||
}
|
||||
|
||||
function summarize(el) {
|
||||
return {
|
||||
tag: el.tagName,
|
||||
text: textOf(el).slice(0, 500),
|
||||
attrs: Array.from(el.attributes || []).reduce((acc, attr) => {
|
||||
acc[attr.name] = attr.value;
|
||||
return acc;
|
||||
}, {}),
|
||||
outerHTML: (el.outerHTML || '').slice(0, 1000),
|
||||
};
|
||||
}
|
||||
|
||||
const view = document.querySelector('[data-testid="complete-drafts-view"]');
|
||||
if (!view) return { ok: false, reason: 'complete drafts view not found' };
|
||||
|
||||
const selectedRows = Array.from(view.querySelectorAll('.ag-center-cols-container [role="row"]'))
|
||||
.filter((row) => isVisible(row) && (row.getAttribute('aria-selected') === 'true' || row.classList.contains('ag-row-selected')));
|
||||
if (!selectedRows.length) return { ok: false, reason: 'no selected complete draft rows' };
|
||||
|
||||
const bulkDropdown = view.querySelector('#bulk-dropdown');
|
||||
if (!bulkDropdown) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: 'bulk dropdown not found',
|
||||
selectedCount: selectedRows.length,
|
||||
};
|
||||
}
|
||||
|
||||
const toggle = bulkDropdown.shadowRoot && bulkDropdown.shadowRoot.querySelector('button[part="dropdown-button-toggle-button"], button');
|
||||
clickElement(toggle || bulkDropdown);
|
||||
|
||||
function findBulkDeleteAction() {
|
||||
const all = [];
|
||||
const seen = new Set();
|
||||
function walk(root) {
|
||||
if (!root || seen.has(root)) return;
|
||||
seen.add(root);
|
||||
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
||||
let node = walker.currentNode;
|
||||
while (node) {
|
||||
if (node.nodeType === Node.ELEMENT_NODE && node.tagName) all.push(node);
|
||||
if (node.shadowRoot) walk(node.shadowRoot);
|
||||
if ((node.tagName || '').toLowerCase() === 'slot' && node.assignedElements) {
|
||||
for (const assigned of node.assignedElements({ flatten: true })) walk(assigned);
|
||||
}
|
||||
node = walker.nextNode();
|
||||
}
|
||||
}
|
||||
walk(document);
|
||||
const exactAction = all.find((el) => {
|
||||
const action = String(el.getAttribute && el.getAttribute('data-action') || '');
|
||||
const text = textOf(el);
|
||||
return isVisible(el) && action === 'DELETE_DRAFTS' && /删除商品信息草稿/.test(text);
|
||||
});
|
||||
if (exactAction) return exactAction;
|
||||
|
||||
return all.find((el) => {
|
||||
const text = textOf(el);
|
||||
const attrs = Array.from(el.attributes || []).map((attr) => `${attr.name}=${attr.value}`).join(' ');
|
||||
const haystack = `${text} ${attrs}`;
|
||||
if (!isVisible(el) || !/删除商品信息草稿/.test(haystack)) return false;
|
||||
if (/^(HTML|BODY|KAT-DATA-GRID)$/i.test(el.tagName || '') && text.length > 80) return false;
|
||||
if (/^DIV$/i.test(el.tagName || '') && text !== '删除商品信息草稿') return false;
|
||||
if ((el.tagName || '').toLowerCase() === 'kat-icon') return false;
|
||||
return /^(BUTTON|KAT-BUTTON|KAT-OPTION|KAT-DROPDOWN-OPTION|LI|A|SPAN|DIV)$/i.test(el.tagName || '');
|
||||
});
|
||||
}
|
||||
|
||||
const deleteAction = findBulkDeleteAction();
|
||||
|
||||
if (!deleteAction) {
|
||||
const candidates = [];
|
||||
const seen = new Set();
|
||||
function walkCandidates(root) {
|
||||
if (!root || seen.has(root)) return;
|
||||
seen.add(root);
|
||||
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
||||
let node = walker.currentNode;
|
||||
while (node) {
|
||||
if (node.nodeType === Node.ELEMENT_NODE && node.tagName && isVisible(node)) {
|
||||
const text = textOf(node);
|
||||
const attrs = Array.from(node.attributes || []).map((attr) => `${attr.name}=${attr.value}`).join(' ');
|
||||
if (/删除|草稿|选择组操作|menu|option/i.test(`${text} ${attrs}`)) candidates.push(summarize(node));
|
||||
}
|
||||
if (node.shadowRoot) walkCandidates(node.shadowRoot);
|
||||
node = walker.nextNode();
|
||||
}
|
||||
}
|
||||
walkCandidates(document);
|
||||
return {
|
||||
ok: false,
|
||||
reason: 'bulk delete draft action not found',
|
||||
menuOpened: true,
|
||||
selectedCount: selectedRows.length,
|
||||
bulkDropdown: summarize(bulkDropdown),
|
||||
candidates: candidates.slice(0, 50),
|
||||
};
|
||||
}
|
||||
|
||||
clickElement(deleteAction);
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
selectedCount: selectedRows.length,
|
||||
bulkDropdown: summarize(bulkDropdown),
|
||||
clicked: summarize(deleteAction),
|
||||
rows: selectedRows.slice(0, 10).map(summarize),
|
||||
};
|
||||
100
app/amazon/scripts/patrol_delete/complete_draft_select_all.js
Normal file
100
app/amazon/scripts/patrol_delete/complete_draft_select_all.js
Normal file
@@ -0,0 +1,100 @@
|
||||
function textOf(node) {
|
||||
return ((node && (node.innerText || node.textContent || '')) || '').replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
function isVisible(el) {
|
||||
if (!el || !el.getBoundingClientRect) return false;
|
||||
const rect = el.getBoundingClientRect();
|
||||
const style = window.getComputedStyle(el);
|
||||
return rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden';
|
||||
}
|
||||
|
||||
function clickElement(el) {
|
||||
el.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||
if (el.focus) el.focus();
|
||||
for (const eventName of ['pointerdown', 'mousedown', 'pointerup', 'mouseup']) {
|
||||
el.dispatchEvent(new MouseEvent(eventName, { bubbles: true, cancelable: true, view: window }));
|
||||
}
|
||||
el.click();
|
||||
}
|
||||
|
||||
function summarizeRow(row) {
|
||||
return {
|
||||
rowId: row.getAttribute('row-id') || '',
|
||||
text: textOf(row).slice(0, 500),
|
||||
selected: row.getAttribute('aria-selected') === 'true' || row.classList.contains('ag-row-selected'),
|
||||
};
|
||||
}
|
||||
|
||||
const payload = arguments[0] || {};
|
||||
const view = document.querySelector('[data-testid="complete-drafts-view"]');
|
||||
if (!view) return { ok: false, reason: 'complete drafts view not found' };
|
||||
|
||||
const rows = Array.from(view.querySelectorAll('.ag-center-cols-container [role="row"]'))
|
||||
.filter((row) => isVisible(row));
|
||||
const rowCount = rows.length;
|
||||
const selectedBefore = rows.filter((row) => row.getAttribute('aria-selected') === 'true' || row.classList.contains('ag-row-selected')).length;
|
||||
const maxSelectCountRaw = Number(payload.maxSelectCount || 0);
|
||||
const maxSelectCount = Number.isFinite(maxSelectCountRaw) && maxSelectCountRaw > 0 ? Math.floor(maxSelectCountRaw) : 0;
|
||||
|
||||
if (payload.probeOnly) {
|
||||
return {
|
||||
ok: true,
|
||||
probeOnly: true,
|
||||
rowCount,
|
||||
selectedCount: selectedBefore,
|
||||
rows: rows.slice(0, 10).map(summarizeRow),
|
||||
};
|
||||
}
|
||||
|
||||
if (rowCount <= 0) {
|
||||
return { ok: false, reason: 'no complete draft rows', rowCount, selectedCount: selectedBefore };
|
||||
}
|
||||
|
||||
const headerCheckbox = view.querySelector('.ag-header-select-all input[type="checkbox"]');
|
||||
if (!headerCheckbox) {
|
||||
return { ok: false, reason: 'complete draft select-all checkbox not found', rowCount, selectedCount: selectedBefore };
|
||||
}
|
||||
|
||||
if (maxSelectCount > 0 && maxSelectCount < rowCount) {
|
||||
if (headerCheckbox.checked) {
|
||||
clickElement(headerCheckbox);
|
||||
}
|
||||
for (const row of rows) {
|
||||
if (row.getAttribute('aria-selected') === 'true' || row.classList.contains('ag-row-selected')) {
|
||||
const checkbox = row.querySelector('input[type="checkbox"]');
|
||||
if (checkbox && checkbox.checked) clickElement(checkbox);
|
||||
}
|
||||
}
|
||||
for (const row of rows.slice(0, maxSelectCount)) {
|
||||
const checkbox = row.querySelector('input[type="checkbox"]');
|
||||
if (checkbox && !checkbox.checked) {
|
||||
clickElement(checkbox);
|
||||
} else if (!checkbox) {
|
||||
clickElement(row);
|
||||
}
|
||||
}
|
||||
} else if (!headerCheckbox.checked || selectedBefore < rowCount) {
|
||||
clickElement(headerCheckbox);
|
||||
}
|
||||
|
||||
let selectedRows = Array.from(view.querySelectorAll('.ag-center-cols-container [role="row"]'))
|
||||
.filter((row) => isVisible(row) && (row.getAttribute('aria-selected') === 'true' || row.classList.contains('ag-row-selected')));
|
||||
|
||||
if (selectedRows.length <= 0) {
|
||||
const firstRowCheckbox = rows[0] && rows[0].querySelector('input[type="checkbox"]');
|
||||
if (firstRowCheckbox && !firstRowCheckbox.checked) {
|
||||
clickElement(firstRowCheckbox);
|
||||
}
|
||||
}
|
||||
|
||||
selectedRows = Array.from(view.querySelectorAll('.ag-center-cols-container [role="row"]'))
|
||||
.filter((row) => isVisible(row) && (row.getAttribute('aria-selected') === 'true' || row.classList.contains('ag-row-selected')));
|
||||
|
||||
return {
|
||||
ok: selectedRows.length > 0,
|
||||
rowCount,
|
||||
selectedCount: selectedRows.length,
|
||||
headerChecked: headerCheckbox.checked,
|
||||
rows: selectedRows.slice(0, 10).map(summarizeRow),
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
function textOf(node) {
|
||||
return ((node && (node.innerText || node.textContent || '')) || '').replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
function isVisible(el) {
|
||||
if (!el || !el.getBoundingClientRect) return false;
|
||||
const rect = el.getBoundingClientRect();
|
||||
const style = window.getComputedStyle(el);
|
||||
return rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden';
|
||||
}
|
||||
|
||||
function clickElement(el) {
|
||||
el.scrollIntoView({ block: 'center', inline: 'nearest' });
|
||||
if (el.focus) el.focus();
|
||||
for (const eventName of ['pointerdown', 'mousedown', 'pointerup', 'mouseup']) {
|
||||
el.dispatchEvent(new MouseEvent(eventName, { bubbles: true, cancelable: true, view: window }));
|
||||
}
|
||||
el.click();
|
||||
}
|
||||
|
||||
function summarize(el) {
|
||||
return {
|
||||
tag: el.tagName,
|
||||
text: textOf(el),
|
||||
className: el.className || '',
|
||||
outerHTML: (el.outerHTML || '').slice(0, 1000),
|
||||
};
|
||||
}
|
||||
|
||||
const targetTag = String((arguments[0] && arguments[0].tag) || '').replace(/\s+/g, ' ').trim();
|
||||
if (!targetTag) return { ok: false, reason: 'target tag empty' };
|
||||
|
||||
const view = document.querySelector('[data-testid="complete-drafts-view"]');
|
||||
if (!view) return { ok: false, reason: 'complete drafts view not found' };
|
||||
|
||||
const chips = Array.from(view.querySelectorAll('.JanusChip-module__janusChipContainer--gRjdp'));
|
||||
const chip = chips.find((el) => {
|
||||
const text = textOf(el);
|
||||
return text === targetTag || text.startsWith(`${targetTag} (`) || text.startsWith(`${targetTag}(`);
|
||||
});
|
||||
|
||||
if (!chip) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: 'complete draft chip not found',
|
||||
tag: targetTag,
|
||||
chips: chips.map(summarize),
|
||||
};
|
||||
}
|
||||
|
||||
if (!/active/.test(String(chip.className || ''))) {
|
||||
clickElement(chip);
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
tag: targetTag,
|
||||
clicked: summarize(chip),
|
||||
};
|
||||
Reference in New Issue
Block a user