Tweetdeck side-scrolling buttons

Tweetdeck buttons for tabbing left/right

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Tweetdeck side-scrolling buttons
// @namespace    https://mileshouse.neocities.org/
// @version      1.2
// @description  Tweetdeck buttons for tabbing left/right
// @author       You
// @match        https://tweetdeck.twitter.com/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tweetdeck.twitter.com
// @grant        GM_registerMenuCommand
// @license MIT
// ==/UserScript==

setTimeout(function() { // 2 second pause before running so tweetdeck can load columns
	'use strict';
	var scrollInterval;
	var distance = 0;
	var targetLoc,targetPixel;
	// targetLoc is the current column index to scroll to, targetPixel is the pixel location of that index
	// currLoc,currPixel same things but where the page is currently scrolled to

	var column = document.querySelector("section.column");
	var container = document.querySelector("#container")
	var width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth; // width of columns;assumes all columns are same
	// * if someone has a custom css with variable column width there will be unexpected behavior

	// buttons html (.stream-item gives it coloration so it can be light/dark)
	var inject = '<div class="lr-scroller stream-item"><div class="scroller-left"><</div><div class="scroller-right">></div></div>';

	// css to use when flipped to top
	var topStyle = `
    .lr-scroller {
        height: 50px;
        width: 100%;
        z-index: 2;
        display: flex;
        left: 0px;
        position: sticky;
    }

    .scroller-left, .scroller-right {
        width: 50%;
        height: 100%;
        font-size: 3em;
        text-align: center;
        user-select: none;
		border-right: black 1px solid;
    }
	`;

	// css to use when flipped to bottom
	var bottomStyle = `
	    .lr-scroller {
        height: 50px;
        width: 100%;
        z-index: 2;
        display: flex;
        left: 0px;
        position: fixed;
		bottom: 0;
		border-top: black 1px solid;
    }

    .scroller-left, .scroller-right {
        width: 50%;
        height: 100%;
        font-size: 3em;
        text-align: center;
        user-select: none;
		border-right: black 1px solid;
    }
	`;
	// insert the css and check the cookie for top/bottom
	var styleSheet = document.createElement("style");
	if (window.localStorage.sidescroll == "bottom") {
		styleSheet.innerText = bottomStyle;

	} else {
		styleSheet.innerText = topStyle;
	}
	document.head.appendChild(styleSheet);

	// insert the buttons html
	container.insertAdjacentHTML("afterbegin", inject);

	// events for clicking the buttons and scrolling on them
	document.querySelector(".scroller-left").addEventListener("click", function(){
		width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
		getNextPos(-1);
		startScrolling();
	});
	document.querySelector(".scroller-right").addEventListener("click", function(){
		width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
		getNextPos(1);
		startScrolling();
	});
	document.querySelector(".lr-scroller").addEventListener("wheel", function(e){
		if (e.deltaY < 0){ //scrolling up
			width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
			getNextPos(-1);
			startScrolling();
		}
		else if (e.deltaY > 0) { //scrolling down
			width = parseInt(getComputedStyle(column).marginRight)+column.clientWidth;
			getNextPos(1);
			startScrolling();
		}
	});

	// updates the target to scroll to
	function getNextPos(x) {
		var currLoc;
		var maxLoc = Math.floor(container.scrollLeftMax/width)+1; // number of scrolling locations plus 1 for the right-most location
		//container.scrollLeft; // current scroll pixel
		currLoc = Math.ceil(container.scrollLeft/width); // index of column currently scrolled to
		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
			currLoc = targetLoc;
		}
		targetLoc = Math.max(currLoc+x, 0); // new target index is left/right 1 index from current location and above 0
		targetLoc = Math.min(targetLoc, maxLoc); // also new target index can't overshoot right
		targetPixel = targetLoc*width; // new target in pixels
		targetPixel = Math.min(targetPixel,container.scrollLeftMax); // if right-most location, make the targ=scrollLeftMax
		// so it doesnt try to overshoot and make a yucky animation
	}

	// yeah we gay keep scrolling
	function startScrolling(){
		if (scrollInterval==null) { // only start new interval if its not already going
			scrollInterval = setInterval(function(){
				var currPixel = container.scrollLeft; // Current Pixel
				distance = targetPixel-currPixel;

				// messy line but it makes it scroll a minimum of 1 pixel unless it's zero
				// if you just do Math.ceil without the 2nd part it will round fractional negative values the wrong way,
				// which will make the interval never reach the terminate condition when it hits -0.
				// the distance/5 part makes it go 20% of the remaining distance per frame,
				// which makes it have a fast->slow smooth animation curve
				container.scrollBy(Math.ceil(Math.abs(distance)/5)*(distance/Math.abs(distance)), 0);

				if (currPixel==targetPixel) { // if reached target, end interval and unset targets
					clearInterval(scrollInterval);
					scrollInterval = null;
					targetLoc = null;
					targetPixel = null;
				}
			}, 1000/60); // interval for 60 fps (1 second divided by 60)
		}
	}

	// this puts the "Flip button" toggle option in the Tamper/Greasemonkey menu
	GM_registerMenuCommand("Flip buttons to top/bottom", function(){
		if (window.localStorage.sidescroll == "bottom") { // flip to top
			window.localStorage.sidescroll = "top"
			styleSheet.innerText = topStyle;

		} else { // flip to bottom
			window.localStorage.sidescroll = "bottom"
			styleSheet.innerText = bottomStyle;
		}
	});

}, 2000);