// ==UserScript== // @name MangaDex Inline Comments // @namespace metapone // @version 1.0.0 // @description Display chapter comments inside MangaDex's sidebar // @author metapone // @license GPL-2.0-only; https://opensource.org/licenses/GPL-2.0 // @homepage https://github.com/metapone/userscript-collection // @supportURL https://github.com/metapone/userscript-collection/issues // @noframes // @match *://mangadex.org/chapter/* // @grant GM_addStyle // @downloadURL none // ==/UserScript== GM_addStyle ('\ /* Fix sidebar stretched outside the screen because of the collapser */\ .no-gutters > .col.reader-controls {\ padding-right: 34px;\ }\ \ /* Fix overlapping flex items */\ .reader-controls-mode, .reader-controls-footer {\ flex-shrink: 0 !important;\ }\ '); function insertComments() { formatSidebar() let xhr = new XMLHttpRequest() xhr.open('GET', '/chapter/'+ lastChapterId + '/comments') xhr.responseType = "document" xhr.addEventListener('load', function() { if (xhr.status === 200) { let htmlDocument = xhr.responseXML.documentElement let posts = htmlDocument.querySelectorAll("table .post") let wrapperNode = document.createElement('div') wrapperNode.setAttribute('class', 'inline-comments') wrapperNode.style.overflow = 'auto' wrapperNode.style.overflowWrap = 'break-word' wrapperNode.style.wordWrap = 'break-word' for (let i = 0; i < posts.length; i++) { let poster = posts[i].querySelector("td:first-child span") let post = posts[i].querySelector(".postbody") let commentNode = document.createElement('div') if (!(i % 2)) commentNode.style.backgroundColor = 'rgba(0,0,0,.05)' commentNode.innerHTML = '
' + poster.innerHTML + '
' + post.innerHTML wrapperNode.appendChild(commentNode) } // Button to redirect to chapter thread let toThread = htmlDocument.querySelector("table+div") if (toThread) wrapperNode.appendChild(toThread) let footerNode = document.querySelector('.reader-controls-footer') footerNode.parentNode.insertBefore(wrapperNode, footerNode) fixSpoilerButton(wrapperNode) } }) xhr.send() } function formatSidebar() { let modeNode = document.querySelector('.reader-controls-mode') let footerNode = document.querySelector('.reader-controls-footer') let pageNode = document.querySelector('.reader-controls-pages') let oldWrapperNodes = document.querySelectorAll('.inline-comments') // Multiple divs can show up if users switch chapter too fast // Clear old comments if (oldWrapperNodes) { for (let i = 0; i < oldWrapperNodes.length; i++) { oldWrapperNodes[i].parentNode.removeChild(oldWrapperNode) } } // Hide sidebar components. Comment out anything you want to keep modeNode.style.setProperty('display', 'none', 'important') // Common keyboard shortcuts footerNode.style.setProperty('display', 'none', 'important') // Footer credit pageNode.style.setProperty('display', 'none', 'important') // Pagination } function fixSpoilerButton(post) { let spoilerBtns = post.querySelectorAll('.btn-spoiler') for (let i = 0; i < spoilerBtns.length; i++) { spoilerBtns[i].addEventListener('click', function() { this.nextElementSibling.classList.toggle('display-none') }) } } let lastPath = '' let lastChapterId = ''; setInterval (function () { if (lastPath !== location.pathname) { lastPath = location.pathname let path = location.pathname.split('/') if (path.length === 4 && !isNaN(path[3]) && lastChapterId !== path[2]) { lastChapterId = path[2] insertComments() } } }, 500)