Tweetdeck side-scrolling buttons

Tweetdeck buttons for tabbing left/right

  1. // ==UserScript==
  2. // @name Tweetdeck side-scrolling buttons
  3. // @namespace https://mileshouse.neocities.org/
  4. // @version 1.2
  5. // @description Tweetdeck buttons for tabbing left/right
  6. // @author You
  7. // @match https://tweetdeck.twitter.com/
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=tweetdeck.twitter.com
  9. // @grant GM_registerMenuCommand
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. setTimeout(function() { // 2 second pause before running so tweetdeck can load columns
  14. 'use strict';
  15. var scrollInterval;
  16. var distance = 0;
  17. var targetLoc,targetPixel;
  18. // targetLoc is the current column index to scroll to, targetPixel is the pixel location of that index
  19. // currLoc,currPixel same things but where the page is currently scrolled to
  20.  
  21. var column = document.querySelector("section.column");
  22. var container = document.querySelector("#container")
  23. var width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth; // width of columns;assumes all columns are same
  24. // * if someone has a custom css with variable column width there will be unexpected behavior
  25.  
  26. // buttons html (.stream-item gives it coloration so it can be light/dark)
  27. var inject = '<div class="lr-scroller stream-item"><div class="scroller-left"><</div><div class="scroller-right">></div></div>';
  28.  
  29. // css to use when flipped to top
  30. var topStyle = `
  31. .lr-scroller {
  32. height: 50px;
  33. width: 100%;
  34. z-index: 2;
  35. display: flex;
  36. left: 0px;
  37. position: sticky;
  38. }
  39.  
  40. .scroller-left, .scroller-right {
  41. width: 50%;
  42. height: 100%;
  43. font-size: 3em;
  44. text-align: center;
  45. user-select: none;
  46. border-right: black 1px solid;
  47. }
  48. `;
  49.  
  50. // css to use when flipped to bottom
  51. var bottomStyle = `
  52. .lr-scroller {
  53. height: 50px;
  54. width: 100%;
  55. z-index: 2;
  56. display: flex;
  57. left: 0px;
  58. position: fixed;
  59. bottom: 0;
  60. border-top: black 1px solid;
  61. }
  62.  
  63. .scroller-left, .scroller-right {
  64. width: 50%;
  65. height: 100%;
  66. font-size: 3em;
  67. text-align: center;
  68. user-select: none;
  69. border-right: black 1px solid;
  70. }
  71. `;
  72. // insert the css and check the cookie for top/bottom
  73. var styleSheet = document.createElement("style");
  74. if (window.localStorage.sidescroll == "bottom") {
  75. styleSheet.innerText = bottomStyle;
  76.  
  77. } else {
  78. styleSheet.innerText = topStyle;
  79. }
  80. document.head.appendChild(styleSheet);
  81.  
  82. // insert the buttons html
  83. container.insertAdjacentHTML("afterbegin", inject);
  84.  
  85. // events for clicking the buttons and scrolling on them
  86. document.querySelector(".scroller-left").addEventListener("click", function(){
  87. width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
  88. getNextPos(-1);
  89. startScrolling();
  90. });
  91. document.querySelector(".scroller-right").addEventListener("click", function(){
  92. width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
  93. getNextPos(1);
  94. startScrolling();
  95. });
  96. document.querySelector(".lr-scroller").addEventListener("wheel", function(e){
  97. if (e.deltaY < 0){ //scrolling up
  98. width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
  99. getNextPos(-1);
  100. startScrolling();
  101. }
  102. else if (e.deltaY > 0) { //scrolling down
  103. width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
  104. getNextPos(1);
  105. startScrolling();
  106. }
  107. });
  108.  
  109. // updates the target to scroll to
  110. function getNextPos(x) {
  111. var currLoc;
  112. var maxLoc = Math.floor(container.scrollLeftMax/width)+1; // number of scrolling locations plus 1 for the right-most location
  113. //container.scrollLeft; // current scroll pixel
  114. currLoc = Math.ceil(container.scrollLeft/width); // index of column currently scrolled to
  115. if (targetLoc != null) { // if target already exists you need to use that as current location, so if you are clicking the buttons fast it can scroll fast
  116. currLoc = targetLoc;
  117. }
  118. targetLoc = Math.max(currLoc+x, 0); // new target index is left/right 1 index from current location and above 0
  119. targetLoc = Math.min(targetLoc, maxLoc); // also new target index can't overshoot right
  120. targetPixel = targetLoc*width; // new target in pixels
  121. targetPixel = Math.min(targetPixel,container.scrollLeftMax); // if right-most location, make the targ=scrollLeftMax
  122. // so it doesnt try to overshoot and make a yucky animation
  123. }
  124.  
  125. // yeah we gay keep scrolling
  126. function startScrolling(){
  127. if (scrollInterval==null) { // only start new interval if its not already going
  128. scrollInterval = setInterval(function(){
  129. var currPixel = container.scrollLeft; // Current Pixel
  130. distance = targetPixel-currPixel;
  131.  
  132. // messy line but it makes it scroll a minimum of 1 pixel unless it's zero
  133. // if you just do Math.ceil without the 2nd part it will round fractional negative values the wrong way,
  134. // which will make the interval never reach the terminate condition when it hits -0.
  135. // the distance/5 part makes it go 20% of the remaining distance per frame,
  136. // which makes it have a fast->slow smooth animation curve
  137. container.scrollBy(Math.ceil(Math.abs(distance)/5)*(distance/Math.abs(distance)), 0);
  138.  
  139. if (currPixel==targetPixel) { // if reached target, end interval and unset targets
  140. clearInterval(scrollInterval);
  141. scrollInterval = null;
  142. targetLoc = null;
  143. targetPixel = null;
  144. }
  145. }, 1000/60); // interval for 60 fps (1 second divided by 60)
  146. }
  147. }
  148.  
  149. // this puts the "Flip button" toggle option in the Tamper/Greasemonkey menu
  150. GM_registerMenuCommand("Flip buttons to top/bottom", function(){
  151. if (window.localStorage.sidescroll == "bottom") { // flip to top
  152. window.localStorage.sidescroll = "top"
  153. styleSheet.innerText = topStyle;
  154.  
  155. } else { // flip to bottom
  156. window.localStorage.sidescroll = "bottom"
  157. styleSheet.innerText = bottomStyle;
  158. }
  159. });
  160.  
  161. }, 2000);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址