Github Stargazers

13.3.2023, 09:34:01

当前为 2023-06-16 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        Github Stargazers
// @namespace   Violentmonkey Scripts
// @match       *://github.com/*/*
// @grant       none
// @version     1.0
// @author      Der_Floh
// @description 13.3.2023, 09:34:01
// @license     MIT
// @icon        https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg
// ==/UserScript==

// jshint esversion: 8
console.info(`%cRunning: ${GM_info.script.name} v${GM_info.script.version}`, 'color: DodgerBlue');



const icon = '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star d-inline-block mr-2"><path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path></svg>';
createTabElem("Stars", icon, (event) => {
  const currentLocation = window.location.toString();
  const subpage = "stargazers";
  const link = `/${getUsername(currentLocation)}/${getRepositoryname(currentLocation)}/${subpage}`;
  window.location.href = link;
});



// | ------------+-------------------+------------ |
// | ------------|  Given Functions  |------------ |
// V ------------+-------------------+------------ V

/**
 * Gets the username of a github url
 * @param {string} url - The url from which to get the username
 * @returns {string} The username of the given github url
 */
function getUsername(url) {
  const parsedUrl = new URL(url);
  const pathSegments = parsedUrl.pathname.split('/');

  if (pathSegments.length >= 3)
    return pathSegments[1];

  return null;
}

/**
 * Gets the repositoryname of a github url
 * @param {string} url - The url from which to get the repositoryname
 * @returns {string} The repositoryname of the given github url
 */
function getRepositoryname(url) {
  const parsedUrl = new URL(url);
  const pathSegments = parsedUrl.pathname.split('/');

  if (pathSegments.length >= 3)
    return pathSegments[2];

  return null;
}

/**
 * Adds a new Tab to a Repository Page
 * @param {string} name - The name of the tab
 * @param {Element} svg - The svg element that specifies the icon of the tab
 * @param {Function} callback - function that specifies what should happen
 * @returns {Element} The created Tab
 */
async function createTabElem(name, svg, callback) {
  const isStargazers = await handleLocalStorage(name);
  const menubar = document.querySelector('ul[class="UnderlineNav-body list-style-none"]');
  const id = menubar.querySelectorAll('li[class="d-inline-flex"]').length;
  let li = document.createElement("li");
  li.dataset.dataViewComponent = true;
  const a = document.createElement("a");
  a.id = name.toLowerCase() + "-tab";
  a.dataset.tabItem = `i${id}${name}-tab`;
  a.dataset.pjax = "#repo-content-pjax-container";
  a.dataset.turboFrame = "repo-content-turbo-frame";
  a.dataset.hotkey = "g c";
  a.dataset.analyticsEvent = '{"category":"Underline navbar","action":"Click tab","label":"Settings","target":"UNDERLINE_NAV.TAB"}';
  a.dataset.viewComponent = "true";
  a.classList.add("UnderlineNav-item", "no-wrap", "js-responsive-underlinenav-item", "js-selected-navigation-item");
  a.addEventListener('click', (event) => {
    event.preventDefault();
    localStorage.setItem(name.toLowerCase(), true);
    callback(event);
  });
  if (isStargazers)
    a.setAttribute("aria-current", "page");

  if (svg && svg != "") {
    let svgElem;
    if (isElement(svg)) {
      svgElem = svg.cloneNode(true);
    } else if (svg.startsWith("http")) {
      svgElem = document.createElement("img");
      svgElem.src = svg;
    } else {
      svgElem = document.createElement("div");
      svgElem.innerHTML = svg;
      svgElem.style.display = "flex";
      svgElem.style.justifyContent = "center";
      svgElem.style.alignItems = "center";
    }
    svgElem.style.maxWidth = "16px";
    svgElem.style.maxHeight = "16px";
    a.appendChild(svgElem);
  }
  const span1 = document.createElement("span");
  span1.dataset.content = name;
  span1.textContent = name;
  a.appendChild(span1);
  const span2 = document.createElement("span");
  span2.id = "code-repo-tab-count";
  span2.dataset.pjaxReplace = "";
  span2.dataset.turboReplace = "";
  span2.title = "Not available";
  span2.dataset.viewComponent = true;
  span2.classList.add("Counter");
  a.appendChild(span2);
  li.appendChild(a);
  menubar.appendChild(li);
  return li;
}

/**
 * Handles the current selected tab inside the localStorage
 * @param {string} tabName - The tabname to handle
 * @returns {boolean} True if the tab is selected
 */
async function handleLocalStorage(tabName) {
  const isStargazers = localStorage.getItem(tabName.toLowerCase()) == "true";
  if (isStargazers)
    localStorage.removeItem(tabName.toLowerCase());

  window.addEventListener("load", () => {
    if (!isStargazers)
      return;
    const tab = document.getElementById(tabName.toLowerCase() + "-tab");
    const intervalId = setInterval(() => {
      if (tab.getAttribute("aria-current") == "page")
        clearInterval(intervalId);
      if (isStargazers)
        tab.setAttribute("aria-current", "page");
    }, 10);
  });

  return isStargazers;
}

/**
 * Checks wether a variable is an Element
 * @param {object} variable - The variable to check
 * @returns {boolean} True if variable is an Element
 */
function isElement(variable) {
  return variable instanceof Element;
}