Expand collapsed GitHub code blocks

Adds click event and distinct hover style to collapsed code indicator

  1. // ==UserScript==
  2. // @name Expand collapsed GitHub code blocks
  3. // @namespace http://tampermonkey.net/
  4. // @description Adds click event and distinct hover style to collapsed code indicator
  5. // @match https://github.com/*
  6. // @version 1.3
  7. // @grant GM_addStyle
  8. // ==/UserScript==
  9.  
  10. // Use with violentmonkey
  11. // https://addons.mozilla.org/en-US/firefox/addon/violentmonkey/
  12. // https://chrome.google.com/webstore/detail/violentmonkey/jinjaccalgkegednnccohejagnlnfdag?hl=en
  13.  
  14. (function () {
  15. "use strict";
  16.  
  17. GM_addStyle(`
  18. .is-hovered.blob-code.blob-code-inner.blob-code-hunk {
  19. background-color: #ffedde !important;
  20. }`);
  21.  
  22. makeCollapsedRegionsClickableAfterLoad();
  23. })();
  24.  
  25. function makeCollapsedRegionsClickableAfterLoad() {
  26. let isLoading = false;
  27.  
  28. const diffContainers = [
  29. ...document.querySelectorAll(".js-diff-progressive-container"),
  30. ];
  31. if (diffContainers.some((c) => showsLoadingIndicator(c))) {
  32. isLoading = true;
  33. }
  34.  
  35. if (isLoading == true) {
  36. window.setTimeout(makeCollapsedRegionsClickableAfterLoad, 5);
  37. } else {
  38. makeCollapsedRegionsClickable();
  39. }
  40. }
  41.  
  42. function makeCollapsedRegionsClickable() {
  43. const expandables = document.querySelectorAll(".js-expandable-line");
  44.  
  45. expandables.forEach((expandable) => {
  46. let line = expandable.querySelector(
  47. ".blob-code.blob-code-inner.blob-code-hunk"
  48. );
  49.  
  50. line = recreateNode(line);
  51. line.style.cursor = "pointer";
  52. line.addEventListener("click", () => expandCodeBlock(expandable));
  53. });
  54. }
  55.  
  56. function expandCodeBlock(line) {
  57. line.querySelector(".blob-num-expandable").children[0].click();
  58. window.setTimeout(makeCollapsedRegionsClickableAfterLoad, 800);
  59. }
  60.  
  61. function showsLoadingIndicator(container) {
  62. return container.querySelectorAll(".diff-progressive-loader").length > 0;
  63. }
  64.  
  65. function recreateNode(el, withChildren) {
  66. if (withChildren) {
  67. const clone = el.cloneNode(true);
  68. el.parentNode.replaceChild(clone, el);
  69. return clone;
  70. } else {
  71. var newEl = el.cloneNode(false);
  72. while (el.hasChildNodes()) newEl.appendChild(el.firstChild);
  73. el.parentNode.replaceChild(newEl, el);
  74. return newEl;
  75. }
  76. }