您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Adds a few useful features to Mangadex
当前为
// ==UserScript== // @name Mangadex Plus // @namespace http://greasyfork.icu/users/553660 // @icon https://mangadex.org/images/misc/navbar.svg // @version 1.0 // @description Adds a few useful features to Mangadex // @author Mr. M // @match https://mangadex.org/* // @grant GM_setValue // @grant GM_getValue // @grant GM_listValues // @grant GM_deleteValue // ==/UserScript== (function() { 'use strict'; /* TODO - Show managa cover on hover */ /* Global values */ var domain = [ "mangadex.org" ] var url = window.location; var nVer = "1.0"; /* Global functions */ // Get the domain from the visiting website function url_domain(data) { var a = document.createElement('a'); a.href = data; return a.hostname; } // Add a global CSS style by inputting a String function addGlobalStyle(css) { var head, style; head = document.getElementsByTagName('head')[0]; if (!head) { return; } style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = css; head.appendChild(style); } // Get site subpage name/directory from provided url function getSubPage(directoryIndex){ let url = document.location.href; var segment = url.replace(/^https?:\/\//, '').split('/')[directoryIndex]; return segment; } // Get current Url function currentUrl(){ return document.location.href; } /* Storage defaults */ let first_time; if (GM_getValue("first_time") != "false"){ first_time = false; GM_setValue("first_time", "false"); //GM_setValue("folders_index", 0); let folders = {"folders" : []}; GM_setValue("folders", JSON.stringify(folders)); let options = {"options" : [{"preloading" : 0}]}; GM_setValue("options", JSON.stringify(options)); GM_setValue("update_notif", "true"); alert("Thank you for installing Mangadex Plus! Go to Settings -> About to learn more about Mangadex Plus!") } // Version check (last version / newest version) if (GM_getValue("version") != nVer && first_time == undefined){ GM_setValue("version", nVer); GM_setValue("update_notif", "true") alert("A feature update is here! MD+ has been updated to " + GM_getValue("version") + "! Check Change Log in MD+ Settings for more info!"); } var red_badge; if (GM_getValue("update_notif") == "true"){ GM_setValue("notif_badge", '<span class="badge badge-danger"> ! </span>') } else{ GM_setValue("notif_badge", '') } /* Site functions */ // Startup functions function startup(){ if (getSubPage(1) == "title"){ main("title"); } else if (getSubPage(1) == "chapter"){ main("chapter") } else{ main("other"); } } /* HTML Elements */ // Color categorizing CSS classes -> "badge" || "text" + "-" + "success"/"danger"/"primary"/nothing //let friends_icon = '<span class="fas fa-user-friends fa-fw text-success" aria-hidden="true"></span>'; //red_badge = '<span class="badge badge-danger"> ! </span>'; //let green_badge = '<span class="badge badge-success"> ! </span>'; //let msg_icon = '<span class="fas fa-envelope fa-fw text-danger" aria-hidden="true"></span>'; let container = document.getElementsByTagName("body")[0]; let pageMask = '<div id="page-mask"></div>'; let closeButton = '<span aria-hidden="true" class="fas fa-times fa-fw plus-clsBtn"> To Exit click anywhere or press <i>Esc</i>.</span>'; /* Functions and features */ function main(level){ let menuButton = '<li id="menuButton" class="nav-item dropdown mx-1 btn btn-secondary">' + '<a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="true"><span class="fas fa-plus-circle fa-fw " aria-hidden="true"></span>' + ' MD Plus ' + GM_getValue("notif_badge") +'</a>' + '<div class="dropdown-menu">' + '<p class="dropdown-item plus-folders"><span class="fas fa-folder fa-fw " aria-hidden="true"></span> Folders</p>' + '<p class="dropdown-item plus-options"><span class="fas fa-list fa-fw " aria-hidden="true"></span> Options</p>' + '<p class="dropdown-item plus-settings"><span class="fas fa-cog fa-fw " aria-hidden="true"></span> Settings ' + GM_getValue("notif_badge") + '</p>' + '</div>' + '</li>'; if (level == "title" || (level == "chapter" || level == "other")){ function mainButton(){ container.insertAdjacentHTML("afterbegin", menuButton); addGlobalStyle("#menuButton { position: fixed; z-index: 99999; top: 10px; right: 15px; list-style-type: none; border-radius: 0.25rem; padding: unset;}"); addGlobalStyle("p.dropdown-item { margin: 0px; }"); folders(); settings(); options(); } mainButton(); } if (level == "title"){ function cardButtons(){ } cardButtons(); actionsBar(); } if (level == "chapter"){ function readerFeatures(){ preload(); } readerFeatures(); } } function closeMenu(){ try{ document.getElementsByClassName("plus-box")[0].remove(); document.getElementById("page-mask").remove(); document.getElementsByClassName("plus-clsBtn")[0].remove(); } catch(e){ //Nothing } try{ document.getElementsByClassName("plus-options-window")[0].remove(); document.getElementById("page-mask").remove(); document.getElementsByClassName("plus-clsBtn")[0].remove(); } catch(e){ //Nothing } } function settings(){ let notes = "(*) This will restore default values for options.</br>" + "(**) This will wipe all Storage data (Folders and entries).</br>" + "(***) This will restore default values for options and wipe storage (Folders and entries)." let items = '<div x-placement="bottom-start" style="left: 0px !important;' + 'right: 0px !important;' + 'width: 800px !important;' + 'margin-left: auto;' + 'margin-right: auto;' + 'margin-top: 100px;' + 'margin-bottom: auto;" class="dropdown-menu show plus-box">' + '<div class="modal-header" style="padding-right: 1rem; padding-bottom: 0.5rem; padding-left: 1rem; padding-top: 0rem;">' + '<h5 class="modal-title" id="homepage_settings_label" style="color: rgb(204, 204, 204) !important;">' + '<span class="fas fa-cog fa-fw " aria-hidden="true"></span> Mangadex Plus Settings</h5>' + '<button type="button" class="close plus-close" data-dismiss="modal" aria-label="Close">' + '<span aria-hidden="true">×</span></button></div>' + '<p class="dropdown-item plus-about" >' + '<span class="fas fa-info fa-fw " aria-hidden="true" ></span> About ' + GM_getValue("notif_badge") + '</p>' + '<p class="dropdown-item plus-change-log" >' + '<span class="fas fa-code fa-fw " aria-hidden="true" ></span> Change Log</p>' + '<p class="dropdown-item plus-reset" style="color: #f90 !important;">' + '<span class="fas fa-undo fa-fw " aria-hidden="true" style="color: #f90 !important;"></span> Reset Defaults (*)</p>' + '<p class="dropdown-item plus-wipe" style="color: #f90 !important;">' + '<span class="fas fa-trash fa-fw " aria-hidden="true" style="color: #f90 !important;"></span> Wipe Storage (**)</p>' + '<p class="dropdown-item plus-reset-wipe" style="color: #f00 !important;">' + '<span class="fas fa-exclamation-triangle fa-fw " aria-hidden="true" style="color: #f00 !important;"></span> Reset & Wipe Mangadex Plus (***)</p>' + '<div class="modal-footer"><p style="margin-bottom: 0px;color: rgb(204,204,204);">' + notes + '</p></div>' '</div>'; function openSettingsMenu(){ container.insertAdjacentHTML("afterbegin", items); addGlobalStyle("div.plus-box { position: fixed !important; right: 700px !important; left: 700px !important; top: 100px !important; z-index: 100001;}"); container.insertAdjacentHTML("afterbegin", pageMask); addGlobalStyle("#page-mask { background: rgba(0, 0, 0, 0.5); position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 100000;}"); container.insertAdjacentHTML("afterbegin", closeButton); addGlobalStyle(".plus-clsBtn { right: 150px !important; position: fixed !important; z-index: 100000; width: auto; color: white; background-color: #444;}"); document.getElementById("page-mask").addEventListener("click", closeMenu); document.getElementsByClassName("plus-clsBtn")[0].addEventListener("click", closeMenu); document.getElementsByClassName("plus-reset-wipe")[0].addEventListener("click", function(){resetMDP("rw")}); document.getElementsByClassName("plus-reset")[0].addEventListener("click", function(){resetMDP("r")}); document.getElementsByClassName("plus-wipe")[0].addEventListener("click", function(){resetMDP("w")}); document.getElementsByClassName("plus-change-log")[0].addEventListener("click", changeLog); document.getElementsByClassName("plus-about")[0].addEventListener("click", about); document.getElementsByClassName("plus-close")[0].addEventListener("click", closeMenu); } function about(){ GM_setValue("update_notif", "false"); GM_setValue("notif_badge", "") let text = "Welcome to Mangadex Plus!<br><br>" + "<b>\"What is Mangadex Plus?\"</b><br>Mangadex Plus is a Userscript that adds some useful features to Mangadex.<br><br>" + "<b>\"What are these Useful features you speak of?\"</b><br>These currently include:</p>" + "<ul><li>Custom folders</li><li>Marking all chapters of a Manga as read/unread</li><li>Start reading button</li>" + "<li>Automatic Chapter Preloading</li></ul>" + "<p>For more info on the features head to the <b>Change Log</b>. As of now these are all but more features will be added through time.<br><br>" + "<b>\"I really want a feature to be added to this script! Do you take suggestions?\"</b><br>I do so Welcomely. Please go to the GreasyFork page of this Userscript and add a suggestion there.<br><br>" + "<b>\"Hey! I found a bug! Where can I report It?\"</b><br> Please report bugs on the GreasyFork page of this Userscript and I'll do my best to fix them ASAP.<br><br>" + '</p><p style="color: gray"> To remove the red badge (<span class="badge badge-danger"> ! </span>) please reload the page.'; let element = '<div x-placement="bottom-start" style="left: 0px !important;' + 'right: 0px !important;' + 'width: 800px !important;' + 'margin-left: auto;' + 'margin-right: auto;' + 'margin-top: 100px;' + 'margin-bottom: auto;" class="dropdown-menu show plus-box">' + '<div class="modal-header" style="padding-right: 1rem; padding-bottom: 0.5rem; padding-left: 1rem; padding-top: 0rem;">' + '<h5 class="modal-title" id="homepage_settings_label" style="color: rgb(204, 204, 204) !important;">' + '<span class="fas fa-info fa-fw " aria-hidden="true"></span> About</h5>' + '<button type="button" class="close plus-close" data-dismiss="modal" aria-label="Close">' + '<span aria-hidden="true">×</span></button></div>' + '<div class="" style="overflow-y: scroll; overflow-x: break-word; max-height: 400px; word-wrap: break-word; color: rgb(204,204,204); padding: 1rem;"><p>' + text + '</p></div>' + '<div class="modal-footer">' + '<a class="btn btn-secondary mx-auto plus-back-settings" style="display: block;width: max-content; color: rgb(204,204,204)">' + '<span class="fas fa-arrow-left fa-fw " aria-hidden="true"></span> Back to Settings</div>' + '</div>'; closeMenu(); container.insertAdjacentHTML("afterbegin", element); addGlobalStyle("div.plus-box { position: fixed !important; right: 700px !important; left: 700px !important; top: 100px !important; z-index: 100001;}"); container.insertAdjacentHTML("afterbegin", pageMask); addGlobalStyle("#page-mask { background: rgba(0, 0, 0, 0.5); position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 100000;}"); container.insertAdjacentHTML("afterbegin", closeButton); addGlobalStyle(".plus-clsBtn { right: 150px !important; position: fixed !important; z-index: 100000; width: auto; color: white; background-color: #444;}"); document.getElementsByClassName("plus-back-settings")[0].addEventListener("click", function(){closeMenu(); settings(); openSettingsMenu();}); document.getElementById("page-mask").addEventListener("click", closeMenu); document.getElementsByClassName("plus-clsBtn")[0].addEventListener("click", closeMenu); document.getElementsByClassName("plus-close")[0].addEventListener("click", closeMenu); } function changeLog(){ let text = "Mangadex Plus version 1.0 is here!<br><br>" + "The very first version brings these features to the table:</p>" + "<ul><li><b>Custom folders:</b> You can make folders and add your chosen titles to It.</li><li><b>Mark all chapters of a Manga as read/unread:</b> " + "Saves you the trouble of having to mark all chapters individually.</li><li><b>Start reading button:</b> Goes to the first chapter of a Manga without having to scroll or switch pages.</li>" + "<li><b>Automatic Chapter Preloading:</b> Whenever you are in the reader (and are logged into your MD Account) the chapter will automatically start preloading. " + "You can turn this feature on/off in th Options Menu.</li></ul><p>" + "I am planning on improving the current features and adding new ones. If you have a suggestion/bug report please let me know on the Userscript's GreasyFork page forum."; let element = '<div x-placement="bottom-start" style="left: 0px !important;' + 'right: 0px !important;' + 'width: 800px !important;' + 'margin-left: auto;' + 'margin-right: auto;' + 'margin-top: 100px;' + 'margin-bottom: auto;" class="dropdown-menu show plus-box">' + '<div class="modal-header" style="padding-right: 1rem; padding-bottom: 0.5rem; padding-left: 1rem; padding-top: 0rem;">' + '<h5 class="modal-title" id="homepage_settings_label" style="color: rgb(204, 204, 204) !important;">' + '<span class="fas fa-code fa-fw " aria-hidden="true"></span> Change Log</h5>' + '<button type="button" class="close plus-close" data-dismiss="modal" aria-label="Close">' + '<span aria-hidden="true">×</span></button></div>' + '<div class="" style="overflow-y: scroll; max-height: 400px; word-wrap: break-word; color: rgb(204,204,204); padding: 1rem;"><p>' + text + '</p></div>' + '<div class="modal-footer">' + '<a class="btn btn-secondary mx-auto plus-back-settings" style="display: block;width: max-content; color: rgb(204,204,204)">' + '<span class="fas fa-arrow-left fa-fw " aria-hidden="true"></span> Back to Settings</div>' + '</div>'; closeMenu(); container.insertAdjacentHTML("afterbegin", element); addGlobalStyle("div.plus-box { position: fixed !important; right: 700px !important; left: 700px !important; top: 100px !important; z-index: 100001;}"); container.insertAdjacentHTML("afterbegin", pageMask); addGlobalStyle("#page-mask { background: rgba(0, 0, 0, 0.5); position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 100000;}"); container.insertAdjacentHTML("afterbegin", closeButton); addGlobalStyle(".plus-clsBtn { right: 150px !important; position: fixed !important; z-index: 100000; width: auto; color: white; background-color: #444;}"); document.getElementsByClassName("plus-back-settings")[0].addEventListener("click", function(){closeMenu(); openSettingsMenu();}); document.getElementById("page-mask").addEventListener("click", closeMenu); document.getElementsByClassName("plus-clsBtn")[0].addEventListener("click", closeMenu); document.getElementsByClassName("plus-close")[0].addEventListener("click", closeMenu); } function resetMDP(level){ function prompt(level){ let text_rw = "WARNING: By confirming this you will DELETE ALL Your Mangadex Plus saved data! This includes options and folders! \nAre you sure you want to proceed?"; let text_r = "WARNING: By confirming this you will RESET ALL Your Mangadex Plus options to Default values! \nAre you sure you want to proceed?"; let text_w = "WARNING: By confirming this you will WIPE ALL Your Mangadex Plus folders and It's Entries! \nAre you sure you want to proceed?"; if (level == "rw"){ if (confirm(text_rw)) { resets("rw"); } } else if (level == "r"){ if (confirm(text_r)) { resets("r"); } } else if (level == "w"){ if (confirm(text_w)) { resets("w"); } } } prompt(level); } function checkKey(e) { e = e || window.event; if (e.keyCode == '27' || e.keyCode == '27') { closeMenu(); } } document.onkeydown = checkKey; document.getElementsByClassName("plus-settings")[0].addEventListener("click", openSettingsMenu); } function folders(){ function getFolders(){ let folders = (JSON.parse(GM_getValue("folders"))).folders; let backFolder = '<p class="dropdown-item plus-disabled"><span class="fas fa-arrow-left fa-fw " aria-hidden="true"></span style="color: #333"> <i>..</i></p>' let createFolder = '<p class="dropdown-item plus-createFolder"><span class="fas fa-plus-circle fa-fw " aria-hidden="true"></span style="color: #333"> <i>Create New Folder</i></p>' let otherFolders = ""; let edit_btn = '<p class="dropdown-item plus-edit-folder" title="Edit Folder Name" style="width: max-content;padding-left: 5px;padding-right: 5px; display: inline-table;">' + '<span aria-hidden="true" class="fas fa-pen fa-fw folder_0"></span></p>'; let delete_btn = '<p class="dropdown-item plus-delete-folder" title="Delete Folder" style="width: max-content;padding-left: 5px;padding-right: 16px;">' + '<span aria-hidden="true" class="fas fa-trash fa-fw folder_0"></span></p>'; for (let i = 0; i < folders.length; i++){ otherFolders = otherFolders + '<div style="display: flex"><p class="dropdown-item "><span class="fas fa-folder-open fa-fw folder_' + (i) + '" aria-hidden="true">' + '</span style="color: #333"> ' + folders[i].name + '</p>' + edit_btn + delete_btn + '</div>'; } return backFolder + otherFolders + createFolder; } function folderItems(index){ let backFolder = '<p class="dropdown-item plus-back"><span class="fas fa-arrow-left fa-fw " aria-hidden="true"></span style="color: #333"> <i>..</i></p>' let folders = (JSON.parse(GM_getValue("folders"))).folders; let folder_name = (JSON.parse(GM_getValue("folders"))).folders[index].name; let delete_btn = '<p class="dropdown-item plus-delete-entry" title="Delete Entry" style="width: max-content;padding-left: 5px;padding-right: 16px;">' + '<span aria-hidden="true" class="fas fa-trash fa-fw folder_0"></span></p>'; let html = ""; for (let i = 0; i < (folders[index].entries).length; i++){ html = html + '<div style="display: flex"><a style="display: contents" href="' + folders[index].entries[i].link + '"><p class="dropdown-item " title="' + folders[index].entries[i].title + '">' + '<span class="fas fa-book fa-fw " aria-hidden="true"></span style="color: #333"> ' + folders[index].entries[i].title + '</p></a>' + delete_btn + '</div>'; } html = backFolder + html; return '<div x-placement="bottom-start" style="left: 0px !important;' + 'right: 0px !important;' + 'width: 600px !important;' + 'margin-left: auto;' + 'margin-right: auto;' + 'margin-top: 100px;' + 'margin-bottom: auto;" class="dropdown-menu show plus-box">' + '<div class="modal-header" style="padding-right: 1rem; padding-bottom: 0.5rem; padding-left: 1rem; padding-top: 0rem;">' + '<h5 class="modal-title" id="homepage_settings_label" style="color: rgb(204, 204, 204) !important;">' + '<span class="fas fa-folder-open fa-fw " aria-hidden="true"></span> ' + folder_name + '</h5>' + '<button type="button" class="close plus-close" data-dismiss="modal" aria-label="Close">' + '<span aria-hidden="true">×</span></button></div>' + html + '</div>'; } function createFolder(){ if (editing_busy == false){ editing_busy = true; function writeFolder(){ let value = "" + document.getElementsByClassName("folderInput")[0].value; let folders = JSON.parse(GM_getValue("folders")); folders.folders[folders.folders.length] = {"name" : value + "", "entries" : []}; GM_setValue("folders", JSON.stringify(folders)); editing_busy = false; } let option = document.getElementsByClassName("dropdown-item plus-createFolder")[0]; option.innerHTML = '<input class="folderInput" type="text" placeholder="When finished writing press Enter"></input>'; document.getElementsByClassName("plus-createFolder")[0].removeEventListener("click", createFolder); function checkKey(e) { e = e || window.event; if (e.keyCode == '13') { writeFolder(); closeMenu(); openFoldersMenu(); document.onkeydown = null } } document.onkeydown = checkKey; document.getElementsByClassName("folderInput")[0].addEventListener("onsubmit", writeFolder); document.getElementsByClassName("folderInput")[0].select(); } } function refreshFolders(){ return '<div x-placement="bottom-start" style="left: 0px !important;' + 'right: 0px !important;' + 'width: 600px !important;' + 'margin-left: auto;' + 'margin-right: auto;' + 'margin-top: 100px;' + 'margin-bottom: auto;" class="dropdown-menu show plus-box">' + '<div class="modal-header" style="padding-right: 1rem; padding-bottom: 0.5rem; padding-left: 1rem; padding-top: 0rem;">' + '<h5 class="modal-title" id="homepage_settings_label" style="color: rgb(204, 204, 204) !important;">' + '<span class="fas fa-folder fa-fw " aria-hidden="true"></span> Folders</h5>' + '<button type="button" class="close plus-close" data-dismiss="modal" aria-label="Close">' + '<span aria-hidden="true">×</span></button></div>' + getFolders() + '</div>'; } function openFoldersMenu(){ container.insertAdjacentHTML("afterbegin", refreshFolders()); addGlobalStyle("div.plus-box { position: fixed !important; right: 700px !important; left: 700px !important; top: 100px !important; z-index: 100001;}"); addGlobalStyle(".plus-disabled{ color: #555}"); addGlobalStyle(".plus-disabled:hover{ background-color: unset; color: #555}"); container.insertAdjacentHTML("afterbegin", pageMask); addGlobalStyle("#page-mask { background: rgba(0, 0, 0, 0.5); position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 100000;}"); container.insertAdjacentHTML("afterbegin", closeButton); addGlobalStyle(".plus-clsBtn { right: 150px !important; position: fixed !important; z-index: 100000; width: auto; color: white; background-color: #444;}"); document.getElementById("page-mask").addEventListener("click", closeMenu); document.getElementsByClassName("plus-clsBtn")[0].addEventListener("click", closeMenu); document.getElementsByClassName("plus-createFolder")[0].addEventListener("click", createFolder); document.getElementsByClassName("plus-close")[0].addEventListener("click", closeMenu); let folders = (JSON.parse(GM_getValue("folders"))).folders; for (let i = 0; i < folders.length; i++){ document.getElementsByClassName("folder_" + i)[0].parentNode.addEventListener("click", function(){browseFolder(i)}); document.getElementsByClassName("plus-delete-folder")[i].addEventListener("click", function(){deleteFolder(i)}); document.getElementsByClassName("plus-edit-folder")[i].addEventListener("click", function(){editFolder(i)}); } } function browseFolder(index){ closeMenu(); container.insertAdjacentHTML("afterbegin", folderItems(index)); addGlobalStyle("div.plus-box { position: fixed !important; right: 700px !important; left: 700px !important; top: 100px !important; z-index: 100001;}"); container.insertAdjacentHTML("afterbegin", pageMask); addGlobalStyle("#page-mask { background: rgba(0, 0, 0, 0.5); position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 100000;}"); container.insertAdjacentHTML("afterbegin", closeButton); addGlobalStyle(".plus-clsBtn { right: 150px !important; position: fixed !important; z-index: 100000; width: auto; color: white; background-color: #444;}"); document.getElementsByClassName("plus-back")[0].addEventListener("click", function(){closeMenu();openFoldersMenu();}) document.getElementById("page-mask").addEventListener("click", closeMenu); document.getElementsByClassName("plus-clsBtn")[0].addEventListener("click", closeMenu); document.getElementsByClassName("plus-close")[0].addEventListener("click", closeMenu); let folders = (JSON.parse(GM_getValue("folders"))).folders[index].entries; for (let i = 0; i < folders.length; i++){ document.getElementsByClassName("plus-delete-entry")[i].addEventListener("click", function(){deleteEntry(index, i)}); } } function deleteFolder(index){ let folder = JSON.parse(GM_getValue("folders")); function prompt(){ if(confirm("Folder " + folder.folders[index].name + " will be deleted. Proceed?")){ folder.folders.splice(index, 1); GM_setValue("folders", JSON.stringify(folder)); closeMenu(); openFoldersMenu(); } } prompt(); } function deleteEntry(folder, entry){ let folders = JSON.parse(GM_getValue("folders")); function prompt(){ if(confirm("\"" + folders.folders[folder].entries[entry].title + "\" will be removed from this Folder. Proceed?")){ folders.folders[folder].entries.splice(entry, 1); GM_setValue("folders", JSON.stringify(folders)); closeMenu(); browseFolder(folder); } } prompt(); } let editing_busy = false; function editFolder(index){ if (editing_busy == false){ editing_busy = true; function writeFolder(){ let value = "" + document.getElementsByClassName("folderInput")[0].value; let folders = JSON.parse(GM_getValue("folders")); folders.folders[index].name = value; GM_setValue("folders", JSON.stringify(folders)); editing_busy = false; } let folder = JSON.parse(GM_getValue("folders")); let option = document.getElementsByClassName("folder_" + index)[0].parentNode; option.innerHTML = '<input class="folderInput" type="text" placeholder="When finished writing press Enter"></input>'; document.getElementsByClassName("folderInput")[0].value = "" + folder.folders[index].name var el = document.getElementsByClassName('folderInput')[0].parentNode, elClone = el.cloneNode(true); el.parentNode.replaceChild(elClone, el); function checkKey(e) { e = e || window.event; if (e.keyCode == '13') { writeFolder(); closeMenu(); openFoldersMenu(); document.onkeydown = null } } document.onkeydown = checkKey; document.getElementsByClassName("folderInput")[0].addEventListener("onsubmit", writeFolder); document.getElementsByClassName("folderInput")[0].select(); } } function checkKey(e) { e = e || window.event; if (e.keyCode == '27' || e.keyCode == '27') { closeMenu(); } } document.onkeydown = checkKey; document.getElementsByClassName("plus-folders")[0].addEventListener("click", openFoldersMenu); addGlobalStyle("p.dropdown-item { overflow: hidden;}"); addGlobalStyle(".plus-delete-folder:hover { color: #f00;}"); addGlobalStyle(".plus-delete-entry:hover { color: #f00;}"); } function options(){ var temp_storage = { "preloading" : JSON.parse(GM_getValue("options")).options[0].preloading } var style = window.getComputedStyle(document.getElementById('homepage_settings_modal')); addGlobalStyle(".plus-options-window {position: fixed; left: 0px !important; right: 0px !important; width: 800px !important; margin-left: auto; margin-right: auto; margin-top: 100px; margin-bottom: auto;)"); addGlobalStyle(".modal-footer{display: block;}"); let preloading = '<div class="form-group row">' + '<label for="language" class="col-lg-3 col-form-label-modal">Auto preloading (*):</label>' + '<div class="col-lg-9">' + '<div class="dropdown bootstrap-select form-control">' + '<select class="form-control selectpicker">' + '<option selected="" value="1">On</option>' + '<option value="0">Off</option>' + '</select>' + '<button type="button" class="btn dropdown-toggle btn-light" data-toggle="dropdown" role="button" data-id="theme_id" title="N">' + '<div class="filter-option">' + '<div class="filter-option-inner">' + '<div class="filter-option-inner-inner plus-preloading-selected"> NaN </div>' + '</div>' + '</div>' + '</button>' + '<div class="dropdown-menu" role="combobox">' + '<div class="inner show" role="listbox" aria-expanded="false" tabindex="-1">' + '<ul class="dropdown-menu inner show plus-preloading-options">' + '<li><a role="option" class="dropdown-item" aria-disabled="false" aria-selected="false" tabindex="0"><span class=" bs-ok-default check-mark"></span><span class="text">On</span></a></li>' + '<li><a role="option" class="dropdown-item" aria-disabled="false" aria-selected="false" tabindex="0"><span class=" bs-ok-default check-mark"></span><span class="text">Off</span></a></li>' + '</ul>' + '</div>' + '</div>' + '</div>' + '</div>' + '</div>'; let notes = '<p style="margin-top: 16px;">(*) Automatically starts preloading chapter when in the reader. Only works for logged-in users.</p>' let options = //'<div id="plus-options-win" class="modal-dialog modal-dialog-centered modal-lg plus-options-window" role="document">' + '<div class="modal-content plus-options-window" style="z-index: 100000">' + '<div class="modal-header">' + '<h5 class="modal-title" id="homepage_settings_label">' + '<span class="fas fa-list fa-fw " aria-hidden="true"></span> Mangadex Plus Options' + '</h5>' + '<button type="button" class="close plus-close" data-dismiss="modal" aria-label="Close">' + '<span aria-hidden="true">×</span>' + '</button>' + '</div>' + '<div class="modal-body">' + '<form method="post" id="homepage_settings_form">' + preloading + '</form>' + '</div>' + '<div class="modal-footer">' + '<a class="btn btn-secondary mx-auto plus-options-save" style="display: block;width: max-content;">' + '<span class="fas fa-save fa-fw " aria-hidden="true"></span> Save' + '</a>' + notes + '</div>' + '</div>'; //'</div>'; function listeners(){ //Listeners for options buttons for(let i = 0; i < document.getElementsByClassName("plus-preloading-options")[0].getElementsByTagName("a").length; i++){ document.getElementsByClassName("plus-preloading-options")[0].getElementsByTagName("a")[i].addEventListener("click", function(){selectOption("preloading", i)}); } document.getElementsByClassName("plus-options-save")[0].addEventListener("click", saveOptions); } function openOptionsMenu(){ container.insertAdjacentHTML("afterbegin", options); addGlobalStyle("div.plus-box { position: fixed !important; right: 700px !important; left: 700px !important; top: 100px !important; z-index: 100001;}"); container.insertAdjacentHTML("afterbegin", pageMask); addGlobalStyle("#page-mask { background: rgba(0, 0, 0, 0.5); position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 100000;}"); container.insertAdjacentHTML("afterbegin", closeButton); addGlobalStyle(".plus-clsBtn { right: 150px !important; position: fixed !important; z-index: 100000; width: auto; color: white; background-color: #444;}"); document.getElementById("page-mask").addEventListener("click", closeMenu); document.getElementsByClassName("plus-clsBtn")[0].addEventListener("click", closeMenu); document.getElementsByClassName("plus-close")[0].addEventListener("click", closeMenu); loadOptions(); listeners(); } function checkKey(e) { e = e || window.event; if (e.keyCode == '27' || e.keyCode == '27') { closeMenu(); } } let sample_options = { "options" : [ { "preloading" : 0 } ] } function saveOptions(){ GM_setValue("options", "{\"options\":[" + JSON.stringify(temp_storage) + "]}") location.reload() } function loadOptions(){ var options = JSON.parse(GM_getValue("options")); let preloading = options.options[0].preloading; selectOption("preloading", preloading); } function selectOption(option, index){ if(option == "preloading"){ let val; for(let i = 0; i < document.getElementsByClassName("plus-preloading-options")[0].getElementsByTagName("a").length; i++){ try{ document.getElementsByClassName("plus-preloading-options")[0].getElementsByTagName("a")[i].classList.remove('selected'); document.getElementsByClassName("plus-preloading-options")[0].getElementsByTagName("a")[i].classList.remove('active'); val = document.getElementsByClassName("plus-preloading-options")[0].getElementsByTagName("a")[index].childNodes[1].innerHTML; } catch(e){/*Nothing*/} } document.getElementsByClassName("plus-preloading-options")[0].getElementsByTagName("a")[index].classList.add("active"); document.getElementsByClassName("plus-preloading-options")[0].getElementsByTagName("a")[index].classList.add("selected"); document.getElementsByClassName("plus-preloading-selected")[0].innerHTML = val; temp_storage.preloading = index; } } document.onkeydown = checkKey; document.getElementsByClassName("plus-options")[0].addEventListener("click", openOptionsMenu); } function actionsBar(){ function makeBar(){ let bar = '<div class="row m-0 py-1 px-0 border-top">' + '<div class="col-lg-3 col-xl-2 strong">Mangadex+ Actions:</div>' + '<div class="col-lg-9 col-xl-10 plus-actionbar">' + '</div>' + '</div>'; var position = document.getElementsByClassName("col-xl-9 col-lg-8 col-md-7")[0]; position.insertAdjacentHTML("beforeend", bar); } function addToFolder(){ function addEntry(index){ let folders = JSON.parse(GM_getValue("folders")); let link = ("" + window.location).replace("#", ""); let pass = true; for(let i = 0; i < folders.folders[index].entries.length; i++){ try{ if(link == folders.folders[index].entries[0].link){ pass = false; } } catch(e){ if (e == TypeError){ pass = true; } } } if (pass == true){ folders.folders[index].entries[folders.folders[index].entries.length] = {"title": "" + document.getElementsByClassName("card-header")[0].childNodes[3].innerHTML, "link" : "" + link}; GM_setValue("folders","" + JSON.stringify(folders)); } } function listFolders(){ let folders = JSON.parse(GM_getValue("folders")); let html = ""; for (let i = 0; i < folders.folders.length; i++){ html = html + '<p class="dropdown-item plus-add-folder-' + i + '" ><span class="fas fa-folder-open fa-fw " aria-hidden="true" ></span> ' + folders.folders[i].name + '</p>'; } return html; } let bar = '<div class="btn-group">' + '<button type="button" class="btn btn-secondary dropdown-toggle plus-folder-trigger" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">' + '<span class="fas fa-plus-circle fa-fw " aria-hidden="true"></span>' + '<span class="d-none d-xl-inline"> Add to Folder</span></button>' + '<div class="dropdown-menu dropdown-menu-right plus-actions-folders">' + listFolders() + '</div>' + '</div> '; let position2 = document.getElementsByClassName("plus-actionbar")[0]; position2.insertAdjacentHTML("beforeend", bar); let folders = JSON.parse(GM_getValue("folders")); for (let i = 0; i < folders.folders.length; i++){ document.getElementsByClassName("plus-add-folder-" + i)[0].addEventListener("click", function(){addEntry(i)}); } function reloadFolders(){ let index = document.getElementsByClassName("plus-actions-folders")[0].childNodes.length for(let i = 0; i < index; i++){ document.getElementsByClassName("plus-add-folder-" + i)[0].remove(); } let position3 = document.getElementsByClassName("plus-actions-folders")[0]; position3.insertAdjacentHTML("afterbegin", listFolders()); let folders = JSON.parse(GM_getValue("folders")); for (let i = 0; i < folders.folders.length; i++){ document.getElementsByClassName("plus-add-folder-" + i)[0].addEventListener("click", function(){addEntry(i)}); } } document.getElementsByClassName("plus-folder-trigger")[0].addEventListener("click", reloadFolders); } function markAs(){ let mark_button = '<div class="btn-group">' + '<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">' + '<span class="fas fa-eye fa-fw " aria-hidden="true"></span>' + '<span class="d-none d-xl-inline"> Mark All As </span></button>' + '<div class="dropdown-menu dropdown-menu-right">' + '<p class="dropdown-item" onclick="javascript:var mark = document.getElementsByClassName(\'chapter_mark_read_button\');for (var i = 0; i < mark.length; i++){mark[i].click();}">' + '<span class="fas fa-eye fa-fw " aria-hidden="true" ></span> Read</p>' + '<p class="dropdown-item" onclick="javascript:var mark = document.getElementsByClassName(\'chapter_mark_unread_button\');for (var i = 0; i < mark.length; i++){mark[i].click();}">' + '<span class="fas fa-eye-slash fa-fw " aria-hidden="true" ></span> Unread</p>' + '</div>' + '</div> '; let position2 = document.getElementsByClassName("plus-actionbar")[0]; position2.insertAdjacentHTML("beforeend", mark_button); } function startReading(){ let manga_id = getSubPage(2); let chapter_id = ""; let api_url = "https://mangadex.org/api/manga/" + manga_id; async function getapi(url) { let response = await fetch(url); var data = await response.json(); var data2 = ""; for(let i = 0; i < Object.entries(data.chapter).length; i++){ if (await Object.entries(Object.entries(data.chapter)[i][1])[3][1] == "English"){ data2 = await Object.entries(data.chapter)[i][0]; break; } } data.chapter[data2] return data2 } getapi(api_url).then(x => { chapter_id = x; let link = "https://mangadex.org/chapter/" + chapter_id; let mark_button = '<button class="btn btn-secondary" onclick="javascript:document.location.href = \'' + link + '\'">' + '<span class="fas fa-book fa-fw"></span>' + '<span class="d-none d-xl-inline"> Start Reading</span>' + '</button>' var position2 = document.getElementsByClassName("plus-actionbar")[0]; position2.insertAdjacentHTML("beforeend", mark_button); }); } makeBar(); addToFolder(); markAs(); startReading(); } function preload(){ async function doPreload(){ let index = 100; for (let i = 0; i < index; i++){ if (document.getElementById("preload-all").getAttribute("disabled") == ""){ await new Promise(r => setTimeout(r, 100)); } else{ document.getElementById("preload-all").click(); i = index; } } } let enabled = (JSON.parse(GM_getValue("options"))).options[0].preloading if (enabled == 0){ doPreload(); } function checkKey(e) { e = e || window.event; if (e.keyCode == '37' || e.keyCode == '39') { doPreload(); } } document.onkeydown = checkKey; document.getElementsByClassName("reader-images col-auto row no-gutters flex-nowrap m-auto text-center cursor-pointer directional constrained")[0].onclick = function(){doPreload()}; } function resets(level){ if(level == "r"){ let options = {"options" : [{"preloading" : 0}]}; GM_setValue("options", JSON.stringify(options)); location.reload(); } else if(level == "w"){ let folders = {"folders" : []}; GM_setValue("folders", JSON.stringify(folders)); location.reload(); } else if(level == "rw"){ let options = {"options" : [{"preloading" : 0}]}; GM_setValue("options", JSON.stringify(options)); let folders = {"folders" : []}; GM_setValue("folders", JSON.stringify(folders)); GM_deleteValue("first_time"); location.reload(); } } startup(); })();