NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name BombManual.com Tab Title and TOC // @downloadURL https://openuserjs.org/install/dperelman/BombManual.com_Tab_Title_and_TOC.user.js // @updateURL https://openuserjs.org/meta/dperelman/BombManual.com_Tab_Title_and_TOC.meta.js // @version 0.1 // @description Update tab title while scrolling and show a table of contents. // @author Daniel Perelman <perelman@aweirdimagination.net> // @license MIT // @match https://www.bombmanual.com/web/* // @match https://bombmanual.com/web/* // @grant none // ==/UserScript== (function() { 'use strict'; window.addEventListener("load", (event) => { const pages = document.getElementsByClassName('page'); const visiblePages = new Map(); function titleFor(el) { let title = el.id; const titles = el.getElementsByClassName('page-header-section-title'); const h2 = el.querySelector('h2'); if (titles.length && !el.id.startsWith("Appendix")) { title = titles[0].innerText; } else if (h2) { title = h2.innerText; } if (title == "www.keeptalkinggame.com") { title = "Title Page"; } else if (title == "Keypads") { title = "Symbols"; } else if (title.startsWith("Appendix")) { title = title.substring(9); } return title; } function updateTitleFor(el) { const title = titleFor(el); document.title = title + " - Keep Talking and Nobody Explodes - Bomb Defusal Manual - en - v1"; } const toc = document.createElement('ul'); for (const page of pages) { if (page.id) { const link = document.createElement('a'); link.href = '#' + page.id; link.innerText = titleFor(page); const item = document.createElement('li'); item.appendChild(link); toc.appendChild(item); } } pages[1].querySelector(".page-content").appendChild(toc); let observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { visiblePages.set(entry.target, entry.intersectionRatio); } else { visiblePages.delete(entry.target); } }); let max = -1; for (const page of pages) { const intersectionRatio = visiblePages.get(page); if (intersectionRatio && intersectionRatio > max) { max = intersectionRatio; updateTitleFor(page); } } }, { threshold: [0, 0.1, 0.25, 0.5, 0.75, 0.9, 1], }); for (const page of pages) { observer.observe(page); } }); })();