自动填写 GitHub 仓库名简化删除操作

在“删除此存储库”按钮上方添加一个按钮,并在 GitHub 上删除存储库时自动填写存储库名称。

  1. // ==UserScript==
  2. // @name Auto Fill Repository Name when Deletion Confirmation
  3. // @name:zh-CN 自动填写 GitHub 仓库名简化删除操作
  4. // @namespace https://github.com/chiperman/GHRepoDeleteHelper
  5. // @version 1.2.1
  6. // @description Add a button above the "Delete this repository" button and auto-fill the repository name when deleting a repository on GitHub.
  7. // @description:zh-CN 在“删除此存储库”按钮上方添加一个按钮,并在 GitHub 上删除存储库时自动填写存储库名称。
  8. // @author chiperman
  9. // @match https://github.com/*
  10. // @grant none
  11. // @icon https://github.githubassets.com/pinned-octocat.svg
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. 'use strict';
  17.  
  18. let observer;
  19.  
  20. const checkURL = () => {
  21. const currentURL = window.location.href;
  22.  
  23. if (currentURL.match(/^https:\/\/github\.com\/.*\/.*\/settings/)) {
  24. const deleteMenuButton = document.getElementById('dialog-show-repo-delete-menu-dialog');
  25.  
  26. if (deleteMenuButton) {
  27. deleteMenuButton.addEventListener('click', clickDeleteRepositoryBtn);
  28. }
  29. }
  30. };
  31.  
  32. const clickDeleteRepositoryBtn = () => {
  33. const targetNode = document.getElementById('repo-delete-menu-dialog');
  34. observer = new MutationObserver(() => handleDialogClick());
  35. const config = { childList: true, subtree: true };
  36. observer.observe(targetNode, config);
  37. };
  38.  
  39. const handleDialogClick = () => {
  40. const buttonElement = document.getElementById('repo-delete-proceed-button');
  41. const buttonLabel = buttonElement.textContent.trim();
  42.  
  43. if (buttonLabel === 'Delete this repository' || buttonLabel === '删除仓库') {
  44. const autoInputBtn = createAutoInputButton();
  45. addButtonToContainer(autoInputBtn, buttonElement);
  46. autoInputBtn.addEventListener('click', autoInputFunction);
  47. observer.disconnect();
  48. }
  49. };
  50.  
  51. const createAutoInputButton = () => {
  52. const button = document.createElement('span');
  53. button.innerText = '🤖 Auto Fill';
  54. button.id = 'auto-input-btn';
  55. button.className =
  56. 'js-repo-delete-proceed-button Button--danger Button--medium Button Button--fullWidth';
  57. button.style.display = 'flex';
  58. button.style.justifyContent = 'center';
  59. button.style.alignItems = 'center';
  60. button.style.marginBottom = '8px';
  61. return button;
  62. };
  63.  
  64. const addButtonToContainer = (autoInputBtn, targetButton) => {
  65. const buttonContainer = targetButton.parentElement;
  66. buttonContainer.insertBefore(autoInputBtn, targetButton);
  67. };
  68.  
  69. const autoInputFunction = () => {
  70. const repositoryElement = document.querySelector('.text-bold.f3.mt-2');
  71. const repositoryName = repositoryElement.textContent.trim();
  72. const inputBlock = document.getElementById('verification_field');
  73. simulateInput(inputBlock, repositoryName);
  74. };
  75.  
  76. // Simulate manually typing each character of the repository name into the input block
  77. const simulateInput = (inputBlock, repositoryName) => {
  78. inputBlock.focus();
  79. inputBlock.value = repositoryName;
  80. const inputEvent = new Event('input');
  81. inputBlock.dispatchEvent(inputEvent);
  82. };
  83.  
  84. checkURL();
  85. const observerConfig = { childList: true, subtree: true };
  86. const mainObserver = new MutationObserver(() => checkURL());
  87. mainObserver.observe(document.body, observerConfig);
  88. })();