Markdown Table Of Contents

Creates a table of contents for some markdown-based websites

  1. // ==UserScript==
  2. // @name Markdown Table Of Contents
  3. // @version 1.1
  4. // @author Rust1667
  5. // @description Creates a table of contents for some markdown-based websites
  6. // @match https://rentry.co/*
  7. // @match https://rentry.org/*
  8. // @match https://*.reddit.com/r/*/wiki/*
  9. // @match https://*.github.io/*
  10. // @match https://saidit.net/s/*/wiki/*
  11. // @match https://wiki.dbzer0.com/*
  12. // @match https://*/*.html
  13. // @grant none
  14. // @namespace https://greasyfork.org/users/980489
  15. // ==/UserScript==
  16.  
  17. (function() {
  18. 'use strict';
  19.  
  20. let currentPageUrl = window.location.href;
  21. let indexContainer = null;
  22.  
  23. function createIndex() {
  24. let subheaderSelector = 'h2[id], h3[id], h4[id], h5[id], h6[id]';
  25.  
  26. // Check if there is more than one h1 subheader
  27. if (document.querySelectorAll('h1[id]').length > 1) {
  28. subheaderSelector = 'h1[id], ' + subheaderSelector;
  29. }
  30.  
  31. const subheaders = document.querySelectorAll(subheaderSelector);
  32. if (subheaders.length === 0) {
  33. removeIndex();
  34. return;
  35. }
  36.  
  37. // Determine the highest subheader tier
  38. let highestTier = 7; // Set to 7 to ensure padding is always greater
  39. subheaders.forEach(subheader => {
  40. const level = parseInt(subheader.tagName[1]);
  41. if (level < highestTier) {
  42. highestTier = level;
  43. }
  44. });
  45.  
  46. // Remove existing index container if it exists
  47. if (indexContainer) {
  48. indexContainer.remove();
  49. }
  50.  
  51. indexContainer = document.createElement('div');
  52. indexContainer.style.position = 'fixed';
  53. indexContainer.style.top = '50%';
  54. indexContainer.style.right = '0';
  55. indexContainer.style.transform = 'translateY(-50%)'; // Adjust to center vertically
  56. indexContainer.style.backgroundColor = getComputedStyle(document.body).getPropertyValue('background-color');
  57. indexContainer.style.border = '1px solid #ced4da';
  58. indexContainer.style.padding = '0'; // Remove padding
  59. indexContainer.style.zIndex = '9999';
  60. indexContainer.style.maxHeight = '80vh';
  61. indexContainer.style.overflowY = 'auto';
  62. indexContainer.style.maxWidth = '200px'; // Limit maximum width
  63.  
  64. const indexList = document.createElement('ul');
  65. indexList.style.margin = '0'; // Remove margin
  66. indexList.style.padding = '0'; // Remove padding
  67. indexList.style.listStyleType = 'none'; // Remove bullet points
  68.  
  69. subheaders.forEach(subheader => {
  70. const listItem = document.createElement('li');
  71. const link = document.createElement('a');
  72. let textContent = subheader.textContent.trim();
  73. // Trim long titles
  74. if (textContent.length > 20) {
  75. textContent = textContent.substring(0, 20) + '...';
  76. }
  77. link.textContent = textContent;
  78. link.href = '#' + subheader.id;
  79. link.style.whiteSpace = 'nowrap'; // Prevent line breaks
  80. link.style.overflow = 'hidden'; // Hide overflowing text
  81. link.style.textOverflow = 'ellipsis'; // Add ellipsis for overflow
  82. const level = parseInt(subheader.tagName[1]);
  83. listItem.style.paddingLeft = (level - highestTier) * 2 + 'em'; // Adjust padding based on the difference from the highest tier
  84. indexList.appendChild(listItem);
  85. listItem.appendChild(link);
  86. });
  87.  
  88. indexContainer.appendChild(indexList);
  89. document.body.appendChild(indexContainer);
  90. }
  91.  
  92. function removeIndex() {
  93. if (indexContainer) {
  94. indexContainer.remove();
  95. indexContainer = null;
  96. }
  97. }
  98.  
  99. function checkUrlChange() {
  100. const newUrl = window.location.href;
  101. if (newUrl !== currentPageUrl) {
  102. currentPageUrl = newUrl;
  103. createIndex();
  104. } else if (!document.querySelector('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]')) {
  105. // Page URL hasn't changed, but no subheaders found
  106. removeIndex();
  107. }
  108. }
  109.  
  110. // Check if the page has subheaders that can be linked to with a URL
  111. const hasSubheaders = document.querySelector('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]');
  112. if (hasSubheaders) {
  113. createIndex();
  114. // Uncommenting the interval check
  115. setInterval(checkUrlChange, 1000); // Check for URL change every second
  116. }
  117. })();