Google Docs Outline Expander

Adds dragable border for google docs outline in order to view long headings.

安裝腳本?
作者推薦腳本

您可能也會喜歡 Google Docs Shortcuts

安裝腳本
  1. // ==UserScript==
  2. // @name Google Docs Outline Expander
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Adds dragable border for google docs outline in order to view long headings.
  6. // @match https://docs.google.com/document/*
  7. // @license MIT
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. const HANDLE_WIDTH = 10;
  15. const VISIBILITY_THRESHOLD = 20;
  16.  
  17. // Observe DOM until sidebar content ("Document tabs") appears
  18. const observer = new MutationObserver((mutations, obs) => {
  19. const readyIndicator = document.querySelector('#kix-outlines-widget-header-text-chaptered');
  20. if (readyIndicator) {
  21. obs.disconnect();
  22. initResizer();
  23. }
  24. });
  25.  
  26. observer.observe(document.body, {
  27. childList: true,
  28. subtree: true
  29. });
  30.  
  31. function initResizer() {
  32. const sidebar = document.querySelector('.left-sidebar-container');
  33. if (!sidebar) {
  34. console.error('Sidebar container not found.');
  35. return;
  36. }
  37.  
  38. let handle = sidebar.querySelector('.left-sidebar-resizer-drag-handle');
  39. if (!handle) {
  40. handle = document.createElement('div');
  41. handle.className = 'left-sidebar-resizer-drag-handle';
  42. sidebar.appendChild(handle);
  43. }
  44.  
  45. Object.assign(handle.style, {
  46. display: 'block',
  47. position: 'absolute',
  48. top: '0',
  49. width: HANDLE_WIDTH + 'px',
  50. height: '100%',
  51. cursor: 'ew-resize',
  52. zIndex: '1000',
  53. background: 'rgba(0,0,0,0.1)',
  54. opacity: '0',
  55. transition: 'opacity 0.2s',
  56. pointerEvents: 'none'
  57. });
  58.  
  59. const initialWidth = sidebar.offsetWidth;
  60. handle.style.left = (initialWidth - HANDLE_WIDTH) + 'px';
  61.  
  62. let isResizing = false;
  63. let startX, startWidth;
  64.  
  65. handle.addEventListener('mousedown', function(e) {
  66. isResizing = true;
  67. startX = e.clientX;
  68. startWidth = sidebar.offsetWidth;
  69. handle.style.opacity = '1';
  70. handle.style.pointerEvents = 'auto';
  71. e.preventDefault();
  72. });
  73.  
  74. document.addEventListener('mousemove', function(e) {
  75. if (isResizing) {
  76. const diffX = e.clientX - startX;
  77. const newWidth = startWidth + diffX;
  78. if (newWidth > 100) {
  79. sidebar.style.width = newWidth + 'px';
  80. handle.style.left = (newWidth - HANDLE_WIDTH) + 'px';
  81. const content = sidebar.querySelector('.left-sidebar-container-content');
  82. if (content) {
  83. content.style.width = (newWidth - HANDLE_WIDTH) + 'px';
  84. }
  85. }
  86. } else {
  87. const rect = sidebar.getBoundingClientRect();
  88. if (e.clientX >= rect.right - VISIBILITY_THRESHOLD && e.clientX <= rect.right + 50) {
  89. handle.style.opacity = '1';
  90. handle.style.pointerEvents = 'auto';
  91. } else {
  92. handle.style.opacity = '0';
  93. handle.style.pointerEvents = 'none';
  94. }
  95. }
  96. });
  97.  
  98. document.addEventListener('mouseup', function() {
  99. if (isResizing) {
  100. isResizing = false;
  101. }
  102. });
  103.  
  104. handle.addEventListener('mouseenter', function() {
  105. handle.style.opacity = '1';
  106. handle.style.pointerEvents = 'auto';
  107. });
  108. handle.addEventListener('mouseleave', function() {
  109. if (!isResizing) {
  110. handle.style.opacity = '0';
  111. handle.style.pointerEvents = 'none';
  112. }
  113. });
  114. }
  115. })();