Hacker News Single click opener

Adds an [l+c] link that opens the url and the comments page in new tabs in one click. Inspired by Reddit Enhancement Suite (/r/Enhancement).

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Hacker News Single click opener
// @namespace    selfdocumentingcode
// @version      0.8
// @description  Adds an [l+c] link that opens the url and the comments page in new tabs in one click. Inspired by Reddit Enhancement Suite (/r/Enhancement).
// @author       selfdocumentingcode@github
// @match        https://news.ycombinator.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ycombinator.com
// @license      MIT
// @grant        GM_openInTab
// @supportURL   https://github.com/selfdocumentingcode/my-random-scripts
// @homepageURL  https://github.com/selfdocumentingcode/my-random-scripts
// ==/UserScript==

(function () {
  "use strict";

  console.log(`Hacker News Single click opener script running ${new Date().toISOString()}`);

  const pageHas4Tables = document.querySelectorAll("table").length === 4;

  if (!pageHas4Tables) return;

  const pageHasTableWithLinks =
    document.querySelectorAll("table > tbody >tr.athing > td.title > span.titleline > a").length > 0;

  const pageHasTableWithCommentLinks =
    document.querySelectorAll('table > tbody > tr > td.subtext > span.subline > a[href^="item"]').length > 0;

  const isRelevantPage = pageHasTableWithLinks && pageHasTableWithCommentLinks;

  if (!isRelevantPage) return;

  const tableWithLinks = document.querySelectorAll("table")[2];

  const tableRows = tableWithLinks.querySelectorAll("tbody > tr");

  for (let i = 0; i < tableRows.length; i++) {
    const tr = tableRows[i];

    // Table rows are a mix of links, comments, spacers, etc.
    // Link rows have the class 'athing' for some reason
    if (!tr.classList.contains("athing")) continue;

    const linkUrl = tr.querySelector("td.title > span.titleline > a")?.href;

    if (!linkUrl) continue;

    // Row with link to comments follows link row
    const commentsTr = tableRows[i + 1];

    // This row and the next can now be skipped
    i += 2;

    const subtextContainer = commentsTr.querySelector("td.subtext > span.subline");

    const isJobsLink = !subtextContainer || subtextContainer.children.length === 1; // There might be a better way to test, but this fits

    // Don't want to show l+c on job posts
    if (isJobsLink) continue;

    const commentsUrl = subtextContainer.querySelector("span.age > a")?.href;

    subtextContainer.appendChild(document.createTextNode(" | "));

    const isExternalLink = linkUrl.indexOf("news.ycombinator.com") < 0;

    const lPlusCLink = document.createElement("a");
    lPlusCLink.href = "javascript:void(0)";
    lPlusCLink.text = isExternalLink ? "[l+c]" : "[l=c]";

    lPlusCLink.onclick = () => {
      // "active: false" opens the tab in the background
      // "insert: true" opens the tab next to the current active tab
      // https://violentmonkey.github.io/api/gm/#gm_openintab
      if (isExternalLink) {
        GM_openInTab(linkUrl, { active: false, insert: true });
      }

      GM_openInTab(commentsUrl, { active: false, insert: true });
    };

    subtextContainer.appendChild(lPlusCLink);
  }
})();