GitHub - Make PRs easier to diff

Add some functionality to github

  1. // ==UserScript==
  2. // @name GitHub - Make PRs easier to diff
  3. // @namespace https://github.com/drKnoxy/
  4. // @version 1.3
  5. // @description Add some functionality to github
  6. // @author DrKnoxy
  7. // @include https://github.com/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function(){
  12. // Toggle headers on click
  13. monitorHeader();
  14.  
  15. // Add whitespace toggle
  16. whitespaceToggles();
  17.  
  18. ////////////////
  19.  
  20. function whitespaceToggles() {
  21. _addToggle();
  22. document.addEventListener('pjax:success', _addToggle);
  23.  
  24. ///
  25.  
  26. function _addToggle() {
  27. const search = _getSearchObj();
  28. const isHidingWhitespace = _isHidingWhitespace(search);
  29.  
  30. // we want the url for the otherway
  31. const newSearch = Object.assign({}, search, {w: _getReverse(search.w)});
  32. const url = _getURL(newSearch);
  33.  
  34. const btn = `
  35.  
  36. `;
  37. const tmpl = `
  38. <div class="diffbar-item">
  39. <a
  40. class="btn btn-sm btn-outline"
  41. href="${url}"
  42. title="Toggle whitespace visibility">
  43. ${isHidingWhitespace ? 'Show' : 'Hide'} whitespace
  44. </a>
  45. </div>
  46. `;
  47.  
  48. // Sometimes we have a PR
  49. const toolbar = document.querySelector('.pr-review-tools');
  50. if (toolbar) {
  51. toolbar.insertAdjacentHTML('afterbegin', tmpl);
  52. }
  53.  
  54. // Sometimes we have a commit
  55. const diffbar = document.querySelector('.js-details-container');
  56. if (diffbar) {
  57. //todo: more here
  58. // diffbar.insertAdjacentHTML('afterbegin', tmpl);
  59. }
  60. }
  61. }
  62.  
  63. function _getReverse(w) {
  64. return (w === 0 || typeof w === 'undefined') ? 1 : 0;
  65. }
  66.  
  67. function _isHidingWhitespace(search) {
  68. return search.w === 1;
  69. }
  70.  
  71. function _getURL(search) {
  72. const newQuery = Object.keys(search).map(k => `${k}=${search[k]}`).join('&');
  73. return `${location.pathname}?${newQuery}`;
  74. }
  75.  
  76. function _getSearchObj() {
  77. if (location.search === '') return {};
  78.  
  79. return location.search
  80. .replace(/^\?/, '')
  81. .split('&')
  82. .reduce((query, p) => {
  83. const [key, val, ...whatev] = p.split('=');
  84. if (key == 'w')
  85. query[key] = parseInt(val, 10);
  86. else
  87. query[key] = val;
  88.  
  89. return query;
  90. }, {});
  91. }
  92.  
  93. function monitorHeader() {
  94. // Attach this event listener up high because
  95. // github uses some fancy pjax to swap content
  96. document.addEventListener('click', _monitor);
  97.  
  98. ///
  99.  
  100. function _monitor(e){
  101. const el = e.target.closest('.file-header');
  102.  
  103. // is this a file header
  104. if (!el) return;
  105.  
  106. // is it next to a blobl-wrapper
  107. const next = el.nextElementSibling;
  108. if (!next.classList.contains('js-file-content')) return;
  109.  
  110. // through the gauntlet
  111. toggleVis(next);
  112. }
  113.  
  114. function toggleVis(el) {
  115. if(el.style.display === '') {
  116. el.style.display = 'none';
  117. } else {
  118. el.style.display = '';
  119. }
  120. }
  121. }
  122.  
  123. })();