AO3: Full Navigation Bar

Adds full navigation bar to AO3.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         AO3: Full Navigation Bar
// @namespace    https://greasyfork.org/
// @version      1.0
// @description  Adds full navigation bar to AO3.
// @author       sopens
// @match        https://archiveofourown.org/works/*/chapters/*
// @grant        none
// ==/UserScript==

// selectedTag exists only when there are several chapters.
var selectedTag = document.getElementById("selected_id");
if (!selectedTag) return;

var ddValue = selectedTag.selectedIndex;
var ddSize = selectedTag.length;
var ddInnerHTML = selectedTag.innerHTML;

var TOP_AND_BOTTOM = false;

// Make hrefs to first and last chapter.
var mainChapterURL = window.location.pathname.split('/').slice(0, 4).join("/") + "/";
var firstHref = mainChapterURL + selectedTag.children[0].value + "#workskin";
var lastHref = mainChapterURL + selectedTag.children[ddSize - 1].value + "#workskin";
var fullPageHref = window.location.pathname.split('/').slice(0, 3).join("/") + "/navigate";

showNavigatorBar();

// Main Functions -------------------------------------------------------------------------

function showNavigatorBar() {
  let topNavBar = document.getElementById("top");
  let btmNavBar = document.getElementById("bottom");

  if (topNavBar != null && btmNavBar != null) return;

  topNavBar = getTopNavBar();
  btmNavBar = getBtmNavBar();

  let navigationTags;

  if (TOP_AND_BOTTOM) {
    navigationTags = [topNavBar, btmNavBar];
  } else {
    showButtonPanel();
    navigationTags = [btmNavBar];
  }

  for (let i = 0; i < navigationTags.length; i++) {
    let firstChapterBtm = createFirstChapterBtm();
    let firstChapterListItem = createListItem(firstChapterBtm, "first");

    let chapterDropdown = createChapterDropdown();
    let chapterDropdownListItem = createListItem(chapterDropdown, "dropdown");

    let lastChapterBtm = createLastChapterBtm();
    let lastChapterListItem = createListItem(lastChapterBtm, "last");

    let fullPageIndexBtm = createFullPageIndexBtm();
    let fullPageIndexListItem = createListItem(fullPageIndexBtm, "full-page-index");

    let navigatorBar = navigationTags[i];
    let entireWorkListItem = navigatorBar.getElementsByClassName("chapter entire")[0];
    let prevChapterListItem = navigatorBar.getElementsByClassName("chapter previous")[0];
    let nextChapterListItem = navigatorBar.getElementsByClassName("chapter next")[0];

    if (ddValue > 1) {
      entireWorkListItem.insertAdjacentElement("afterend", firstChapterListItem);
    }

    if (ddValue == 0) {
      entireWorkListItem.insertAdjacentElement("afterend", chapterDropdownListItem);
    } else {
      prevChapterListItem.insertAdjacentElement("afterend", chapterDropdownListItem);
    }

    if (ddValue < (ddSize - 2)) {
      nextChapterListItem.insertAdjacentElement("afterend", lastChapterListItem);
    }

    if (ddValue == (ddSize - 2)) {
      nextChapterListItem.insertAdjacentElement("afterend", fullPageIndexListItem);
    }

    if (ddValue < (ddSize - 1)) {
      lastChapterListItem.insertAdjacentElement("afterend", fullPageIndexListItem);
    }
  }
}

function showButtonPanel() {
  let buttonPanel = document.getElementById("button_panel");

  if (buttonPanel != null) return;

  let listHeader = document.createElement("dt");
  listHeader.appendChild(document.createTextNode("Navigation Panel:"));

  let listContent = document.createElement("dd");
  let buttonList = document.createElement("ul");
  listContent.appendChild(buttonList);

  buttonPanel = document.getElementsByClassName("work meta group")[0];
  buttonPanel.id = "button_panel";
  buttonPanel.appendChild(listHeader);
  buttonPanel.appendChild(listContent);

  let entireWorkBtm = createEntireWorkBtm();
  addStyle(entireWorkBtm);

  let entireWorkListItem = createListItem(entireWorkBtm, "entire");
  buttonList.appendChild(entireWorkListItem);

  if (ddValue > 1) {
    let firstChapterBtm = createFirstChapterBtm();
    addStyle(firstChapterBtm);

    let firstChapterListItem = createListItem(firstChapterBtm, "first");
    buttonList.appendChild(firstChapterListItem);
  }

  if (ddValue > 0) {
    let prevChapterBtm = createPrevChapterBtm();
    addStyle(prevChapterBtm);

    let prevChapterListItem = createListItem(prevChapterBtm, "previous");
    buttonList.appendChild(prevChapterListItem);
  }

  let chapterDropdown = createChapterDropdown();
  let chapterDropdownListItem = createListItem(chapterDropdown, "dropdown");

  buttonList.appendChild(chapterDropdownListItem);

  if (ddValue < (ddSize - 1)) {
    let nextChapterBtm = createNextChapterBtm();
    addStyle(nextChapterBtm);

    let nextChapterListItem = createListItem(nextChapterBtm, "previous");
    buttonList.appendChild(nextChapterListItem);
  }

  if (ddValue < (ddSize - 2)) {
    let lastChapterBtm = createLastChapterBtm();
    addStyle(lastChapterBtm);

    let lastChapterListItem = createListItem(lastChapterBtm, "last");
    buttonList.appendChild(lastChapterListItem);
  }

  let fullPageIndexBtm = createFullPageIndexBtm();
  addStyle(fullPageIndexBtm);

  let fullPageIndexListItem = createListItem(fullPageIndexBtm, "full-page-index");
  buttonList.appendChild(fullPageIndexListItem);
}

// Global Functions ------------------------------------------------------------------

function getTopNavBar() {
  let navBar = document.getElementById("chapter_index").parentElement.parentElement;
  navBar.id = "top";

  if (!TOP_AND_BOTTOM) {
    let entireWorkListItem = navBar.getElementsByClassName("chapter entire")[0];
    entireWorkListItem.remove();

    let prevChapterListItem = navBar.getElementsByClassName("chapter previous")[0];
    if (prevChapterListItem != null) prevChapterListItem.remove();

    let nextChapterListItem = navBar.getElementsByClassName("chapter next")[0];
    if (nextChapterListItem != null) nextChapterListItem.remove();
  }

  let topListItems = navBar.getElementsByTagName("li");

  for (let i = 0; i < topListItems.length; i++) {
    let topLink = topListItems[i].getElementsByTagName("a")[0];

    if (topLink.text.search("Chapter Index") != -1) {
      topListItems[i].remove();
      break;
    }
  }

  return navBar;
}

function getBtmNavBar() {
  let navBar = document.getElementById("feedback").getElementsByTagName("ul")[0];
  navBar.id = "bottom";

  let btmListItems = navBar.getElementsByTagName("li");

  for (let i = 0; i < btmListItems.length; i++) {
    let btmLink = btmListItems[i].getElementsByTagName("a")[0];

    if (btmLink == null) continue;

    if (btmLink.text.search("Top") != -1) {
      btmListItems[i].className = "chapter entire";
      continue;
    }

    if (btmLink.text.search("Previous") != -1) {
      btmListItems[i].className = "chapter previous";
      continue;
    }

    if (btmLink.text.search("Next") != -1) {
      btmListItems[i].className = "chapter next";
      break;
    }
  }

  return navBar;
}

function createListItem(element, className) {
  let listItem = document.createElement("li");
  listItem.className = "chapter " + className;
  listItem.appendChild(document.createTextNode("\n\n"));
  listItem.appendChild(element);
  listItem.appendChild(document.createTextNode("\n\n"));

  return listItem;
}

function createChapterDropdown() {
  let dropdown = document.createElement("select");
  addStyle(dropdown);
  dropdown.id = "chapter_list";
  dropdown.innerHTML = ddInnerHTML;
  dropdown.style.padding = ".18em .75em";
  dropdown.onchange = function() {
    let selectedValue = this.options[this.selectedIndex].value;
    window.location.href = mainChapterURL + selectedValue + "#workskin";
  }

  return dropdown;
}

function createEntireWorkBtm() {
  let href = window.location.pathname.split('/').slice(0, 3).join("/") + "?view_full_work=true";

  return createBtm(href, "Entire Work");
}  

function createFirstChapterBtm() {
  return createBtm(firstHref, "<< First Chapter");
}  

function createPrevChapterBtm() {
  let href = mainChapterURL + selectedTag.children[ddValue - 1].value + "#workskin";

  return createBtm(href, "< Previous Chapter");
}  

function createNextChapterBtm() {
  let href = mainChapterURL + selectedTag.children[ddValue + 1].value + "#workskin";

  return createBtm(href, "Next Chapter >");
}  

function createLastChapterBtm() {  
  return createBtm(lastHref, "Last Chapter >>");
}  

function createFullPageIndexBtm() {  
  return createBtm(fullPageHref, "Full-page Index");
}  

function createBtm(href, text) {
  let link = document.createElement("a");
  link.href = href;
  link.appendChild(document.createTextNode(text));

  return link;
}

function addStyle(element) {
  element.style.display = "inline-block";
  element.style.verticalAlign = "middle";
  element.style.backgroundColor = "#eee";
  element.style.color = "#444";
  element.style.width = "auto";
  element.style.fontSize = "100%";
  element.style.lineHeight = "1.286";
  element.style.padding = ".25em .75em";
  element.style.whiteSpace = "nowrap";
  element.style.overflow = "visible";
  element.style.position = "relative";
  element.style.cursor = "pointer";
  element.style.textDecoration = "none";
  element.style.backgroundImage = "linear-gradient(#fff 2%,#ddd 95%,#bbb 100%)";
  element.style.border = "1px solid #bbb";
  element.style.borderRadius = ".25em";
  element.style.boxShadow = "none";
  element.style.margin = "0px";
  element.style.font = "inherit";
}