(page: Page, index?: number)
| 610 | * Undo a modification by index (or last if no index given). |
| 611 | */ |
| 612 | export async function undoModification(page: Page, index?: number): Promise<void> { |
| 613 | const idx = index ?? modificationHistory.length - 1; |
| 614 | if (idx < 0 || idx >= modificationHistory.length) { |
| 615 | const evictedNote = modHistoryTotalPushed > MOD_HISTORY_CAP |
| 616 | ? ` (most recent ${MOD_HISTORY_CAP} only — ${modHistoryTotalPushed - MOD_HISTORY_CAP} earlier entries evicted at the cap)` |
| 617 | : ''; |
| 618 | throw new Error( |
| 619 | `No modification at index ${idx}. History has ${modificationHistory.length} entries${evictedNote}.`, |
| 620 | ); |
| 621 | } |
| 622 | |
| 623 | const mod = modificationHistory[idx]; |
| 624 | |
| 625 | if (mod.method === 'setStyleTexts') { |
| 626 | // Try to restore via CDP |
| 627 | try { |
| 628 | await modifyStyle(page, mod.selector, mod.property, mod.oldValue); |
| 629 | // Remove the undo modification from history (it's a restore, not a new mod) |
| 630 | modificationHistory.pop(); |
| 631 | } catch (err: any) { |
| 632 | // Fall back to inline restore — CDP may have disconnected or stylesheet changed |
| 633 | if (!err?.message?.includes('closed') && !err?.message?.includes('Target') && !err?.message?.includes('style') && !err?.message?.includes('not found') && !err?.message?.includes('Element')) throw err; |
| 634 | await page.evaluate( |
| 635 | ([sel, prop, val]) => { |
| 636 | const el = document.querySelector(sel); |
| 637 | if (!el) return; |
| 638 | if (val) { |
| 639 | (el as HTMLElement).style.setProperty(prop, val); |
| 640 | } else { |
| 641 | (el as HTMLElement).style.removeProperty(prop); |
| 642 | } |
| 643 | }, |
| 644 | [mod.selector, mod.property, mod.oldValue] |
| 645 | ); |
| 646 | } |
| 647 | } else { |
| 648 | // Inline modification — restore or remove |
| 649 | await page.evaluate( |
| 650 | ([sel, prop, val]) => { |
| 651 | const el = document.querySelector(sel); |
| 652 | if (!el) return; |
| 653 | if (val) { |
| 654 | (el as HTMLElement).style.setProperty(prop, val); |
| 655 | } else { |
| 656 | (el as HTMLElement).style.removeProperty(prop); |
| 657 | } |
| 658 | }, |
| 659 | [mod.selector, mod.property, mod.oldValue] |
| 660 | ); |
| 661 | } |
| 662 | |
| 663 | modificationHistory.splice(idx, 1); |
| 664 | } |
| 665 | |
| 666 | /** |
| 667 | * Get the full modification history. |
no test coverage detected