/*==================================================== // MLPForums Plus (JS) v1.5.1 // Author: Rikifive //==================================================*/ /*==================================================== | * * * CONFIGURATION * * * ====================================================*/ // === FAVORITES === //---------------------------------------------------- // Configure links here. // ["title"] => creates an unclickable section // ["title", "link"] => creates a clickable option // Remember about commas after every entry, except the last one. //---------------------------------------------------- const FAVORITES = [ ["MLP:FiM Canon Discussion"], ["Season 1 Discussion","https://mlpforums.com/forum/11-season-1-discussion/"], ["Season 2 Discussion","https://mlpforums.com/forum/58-season-2-discussion/"], ["Season 3 Discussion","https://mlpforums.com/forum/59-season-3-discussion/"], ["Season 4 Discussion","https://mlpforums.com/forum/119-season-4-discussion/"], ["Season 5 Discussion","https://mlpforums.com/forum/167-season-5-discussion/"], ["Season 6 Discussion","https://mlpforums.com/forum/214-season-6-discussion/"], ["Season 7 Discussion","https://mlpforums.com/forum/259-season-7-discussion/"], ["My Little Pony: The Movie (2017)", "https://mlpforums.com/forum/219-my-little-pony-the-movie-2017/"], ["Season 8 Discussion","https://mlpforums.com/forum/270-season-8-discussion/"], ["Season 9 Discussion","https://mlpforums.com/forum/311-season-9-discussion/"], ["Specials and Shorts","https://mlpforums.com/forum/331-specials-and-shorts/"], ["Canterlot Gallery"], ["Visual Fan Art","https://mlpforums.com/forum/18-visual-fan-art/"], ["Fan Music","https://mlpforums.com/forum/30-fan-music/"], ["Science!"], ["Testing Forum", "https://mlpforums.com/forum/110-testing-forum/"] ]; // end of favorites // === FOLLOWED FORUMS === // Be notified about unread posts in the forums of your choice. // The notifications will appear on a new dedicated userbar button. //---------------------------------------------------- // *** Enable feature? (true/false) //---------------------------------------------------- const ENABLE_FOLLOWING_FORUMS = true; //---------------------------------------------------- // Specify forums you want to be notified about unread posts. // syntax: FOLLOWED_FORUMS = array[string]; // example: FOLLOWED_FORUMS = ["MLP:FiM Canon Discussion", "Visual Fan Art", "Throne Room"]; // // Note, that you can specify the entire section or only its subforums of your choice. // Caution: It is case-sensitive, so be sure to put names exactly like they are on the forums. //---------------------------------------------------- const FOLLOWED_FORUMS = ["Throne Room", "Support"]; //---------------------------------------------------- // Print console logs? (true/false) // (logs will appear in browser debug console if enabled) //---------------------------------------------------- const LOGS = false; /*==================================================== | * * * END OF CONFIGURATION * * * | /!\ Do NOT edit anything past this point unless you know what you are doing! ====================================================*/ /*======================================= // Console Logs =======================================*/ const CP = "color:#ff1; background-color:#f69; font-weight:bold"; const CN = "color:initial"; const CS = "color:#5f5"; const CW = "color:#f55; background-color:#300; font-weight:bold"; if (LOGS) { console.log("%c[MLPF+]%c --- Loading MLPForums Plus ---", CP, "color:#f8b"); } /*======================================= // Sticky UserNav =======================================*/ let nav, navContainer, headerContainer; document.addEventListener("DOMContentLoaded", function() { if (LOGS) { console.log("%c[MLPF+]%c Initializing Sticky UserNav...", CP, CN); } nav = document.getElementById("elUserNav"); if (!nav) { if (LOGS) { console.log("%c[MLPF+]%c ERROR: Failed to initialize UserNav", CP, CW); } return; } setupUserNav(); addNavBtns(); updateScroll(); window.addEventListener('scroll', updateScroll); if (LOGS) { console.log("%c[MLPF+]%c UserNav initialized successfully", CP, CS); } }) // Setup User Navbar function setupUserNav() { // Wrap UserNav in container and move to the body navContainer = document.createElement("div"); navContainer.id = "elUserNavContainer"; headerContainer = document.getElementById("elUserNav").parentNode; headerContainer.appendChild(navContainer); navContainer.appendChild(nav); // Mark Default UserNav Menus let mnu = document.querySelectorAll('#elUserNav > li > *[id$="_menu"]'); mnu.forEach(e => e.classList.add("userNavMenu")); } // Add Extra Buttons to the left function addNavBtns() { let count = 0; // Home & Status Updates let button = [ { title: "Return to Home Page", link: "https://mlpforums.com/", icon: "home", text: " Home" }, { title: "View All Status Updates", link: "https://mlpforums.com/discover/23/", icon: "newspaper-o", text: " Status Updates" } ] let i, li, a, ico; for (i = 0; i < button.length; i++) { nav.insertBefore(li = document.createElement("li"), nav.childNodes[count++]); li.classList.add("cExtraBtn"); li.appendChild(a = document.createElement("a")); a.setAttribute("data-ipstooltip", ""); a.setAttribute("_title", button[i].title); a.href = button[i].link; a.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-" + button[i].icon); a.appendChild(document.createTextNode(button[i].text)); } // Forums let section = [ ["All About Ponies"], ["Start Here!", "https://mlpforums.com/forum/211-start-here/"], ["My Little Pony", "https://mlpforums.com/forum/1-my-little-pony/"], ["Octavia's Hall", "https://mlpforums.com/forum/4-octavias-hall-fan-art-more/"], ["Roleplaying, Fun & Discussions"], ["Roleplay World", "https://mlpforums.com/forum/21-roleplay-world/"], ["Events", "https://mlpforums.com/forum/176-events/"], ["Beyond Equestria", "https://mlpforums.com/forum/5-beyond-equestria/"], ["MLP Forums Meta"], ["Canterlot", "https://mlpforums.com/forum/20-canterlot-mlp-forums-meta/"], ["More"], ["Poniverse", "https://mlpforums.com/forum/67-poniverse/"], ["Conventions", "https://mlpforums.com/forum/135-conventions/"] ] nav.insertBefore(li = document.createElement("li"), nav.childNodes[count++]); li.classList.add("cExtraBtn", "cForumsList"); li.appendChild(a = document.createElement("a")); a.setAttribute("data-ipstooltip", ""); a.setAttribute("_title", "Browse Forums"); a.href = "#elForumsList_menu"; a.id = "elForumsList"; a.setAttribute("data-ipsmenu", ""); a.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-navicon"); a.appendChild(document.createTextNode(" Forums ")); a.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-caret-down"); let ul, opt; li.appendChild(ul = document.createElement("ul")); ul.id = "elForumsList_menu"; ul.classList.add("ipsMenu", "ipsMenu_normal", "ipsHide", "userNavMenu"); ul.setAttribute("style", "position: fixed; top: 32px; display: none;"); for (i = 0; i < section.length; i++) { ul.appendChild(opt = document.createElement("li")); if (section[i][1]) { opt.classList.add("ipsMenu_item"); opt.appendChild(a = document.createElement("a")); a.href = section[i][1]; a.appendChild(document.createTextNode(section[i][0])); } else { opt.classList.add("ipsMenu_title"); opt.appendChild(document.createTextNode(section[i][0])); } } // Favorites nav.insertBefore(li = document.createElement("li"), nav.childNodes[count++]); li.classList.add("cExtraBtn", "cFavList"); li.appendChild(a = document.createElement("a")); a.setAttribute("data-ipstooltip", ""); a.setAttribute("_title", "Browse Favorite Places"); a.href = "#elFavList_menu"; a.id = "elFavList"; a.setAttribute("data-ipsmenu", ""); a.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-star"); a.appendChild(document.createTextNode(" Favorites ")); a.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-caret-down"); li.appendChild(ul = document.createElement("ul")); ul.id = "elFavList_menu"; ul.classList.add("ipsMenu", "ipsMenu_normal", "ipsHide", "userNavMenu"); ul.setAttribute("style", "position: fixed; top: 32px; display: none;"); for (i = 0; i < FAVORITES.length; i++) { ul.appendChild(opt = document.createElement("li")); if (FAVORITES[i][1]) { opt.classList.add("ipsMenu_item"); opt.appendChild(a = document.createElement("a")); a.href = FAVORITES[i][1]; a.appendChild(document.createTextNode(FAVORITES[i][0])); } else { opt.classList.add("ipsMenu_title"); opt.appendChild(document.createTextNode(FAVORITES[i][0])); } } // SEPARATOR nav.insertBefore(li = document.createElement("li"), nav.childNodes[count++]); li.classList.add("cExtraBtn", "elUserNav_sep"); // FAQ nav.insertBefore(li = document.createElement("li"), nav.childNodes[count++]); li.classList.add("cExtraBtn", "iconOnly", "cUserNav_icon"); li.appendChild(a = document.createElement("a")); a.setAttribute("data-ipstooltip", ""); a.setAttribute("_title", "Site FAQ"); a.href = "https://mlpforums.com/faq/"; a.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-book"); // ROLEPLAY CHARACTERS nav.insertBefore(li = document.createElement("li"), nav.childNodes[count++]); li.classList.add("cExtraBtn", "iconOnly", "cUserNav_icon"); li.appendChild(a = document.createElement("a")); a.setAttribute("data-ipstooltip", ""); a.setAttribute("_title", "My Roleplay Characters"); a.href = "https://mlpforums.com/characters/?filter=characters_mine"; a.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-address-card"); // FOLLOWED FORUMS if (ENABLE_FOLLOWING_FORUMS && document.body.getAttribute("data-pagecontroller") == "index") { let unreadForums = []; let uForumsAll = document.querySelectorAll('.cForumList .ipsDataItem_unread .ipsDataItem_main .ipsDataItem_title a, .cForumList .ipsDataItem_main .ipsDataItem_subList .ipsDataItem_unread a'); let uForumName; for (i = 0; i < uForumsAll.length; i++) { uForumName = uForumsAll[i].innerText.trim(); if (FOLLOWED_FORUMS.includes(uForumName)) { unreadForums.push([uForumName, uForumsAll[i].href]); } } nav.insertBefore(li = document.createElement("li"), nav.childNodes[count++]); li.classList.add("cExtraBtn", "iconOnly", "cUserNav_icon", "cUnreadForums"); li.appendChild(a = document.createElement("a")); a.setAttribute("data-ipstooltip", ""); a.setAttribute("_title", "Unread Forums"); a.href = "#elUnreadForums_menu"; a.id = "elUnreadForums"; a.setAttribute("data-ipsmenu", ""); a.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-comments"); if (unreadForums.length > 0) { let count; a.appendChild(count = document.createElement("span")); count.classList.add("ipsNotificationCount"); count.setAttribute("style", "right: -5px; top: -5px;"); count.innerText = unreadForums.length; } li.appendChild(ul = document.createElement("ul")); ul.id = "elUnreadForums_menu"; ul.classList.add("ipsMenu", "ipsMenu_normal", "ipsHide", "userNavMenu"); ul.setAttribute("style", "position: fixed; top: 32px; display: none;"); ul.appendChild(opt = document.createElement("li")); opt.classList.add("ipsMenu_title"); opt.appendChild(document.createTextNode("Unread Forums")); opt.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-gears", "cUnreadTestBtn"); ico.addEventListener("click", function() { let tForumsAll = document.querySelectorAll('.cForumList .ipsDataItem_main .ipsDataItem_title a, .cForumList .ipsDataItem_main .ipsDataItem_subList a'); let tForumName; for (i = 0; i < tForumsAll.length; i++) { tForumName = tForumsAll[i].innerText.trim(); if (FOLLOWED_FORUMS.includes(tForumName)) { tForumsAll[i].classList.add("verified-follow"); } } alert("Test Successful.\nCheck if the forums you follow are highlighed on the main page."); }); ico.setAttribute("data-ipstooltip", ""); ico.setAttribute("_title", "Test Followed Forums"); if (unreadForums.length == 0) { ul.appendChild(opt = document.createElement("li")); opt.classList.add("ipsMenu_item"); opt.setAttribute("style", "padding: 11px 20px;"); opt.appendChild(document.createTextNode("~ There's nothing here ~")); } else { for (i = 0; i < unreadForums.length; i++) { ul.appendChild(opt = document.createElement("li")); opt.classList.add("ipsMenu_item"); opt.appendChild(a = document.createElement("a")); a.href = unreadForums[i][1]; a.appendChild(document.createTextNode(unreadForums[i][0])); } } } // SEPARATOR nav.insertBefore(li = document.createElement("li"), nav.childNodes[count++]); li.classList.add("cExtraBtn", "elUserNav_sep", "lastExtraSep"); // RANK let expTable = [0,5,40,100,200,300,400,500,600,750,1000,1250,1500,1750,2000,2500,3000,4000,5000,6000,7000,8000,10000]; let rankObj = document.querySelector('#elUserLink_menu .elUserNav_achievements img'); if (rankObj) { let level = Number(rankObj.getAttribute("title").match(/\d+/)[0]); let rankImg = rankObj.getAttribute("src"); if (level < expTable.length) { var toNext = parseInt(document.querySelector("#elUserLink_menu div.ipsType_small").innerText); var totalExp = expTable[level] - toNext; var currExp = totalExp - expTable[level-1]; var reqExp = expTable[level] - expTable[level-1]; var expRate = currExp / reqExp * 100; } nav.insertBefore(li = document.createElement("li"), nav.childNodes[count++]); li.classList.add("rankBox", "stickyOnly"); a = li.appendChild(document.createElement("a")); a.href = "https://mlpforums.com/faq/site-problems/user-and-staff-ranks-r116/" a.setAttribute("data-ipsdialog", ""); let divLevel = a.appendChild(document.createElement("div")); divLevel.id = "divLevel"; divLevel.setAttribute("data-ipstooltip", ""); divLevel.setAttribute("_title", "Your Rank"); let rankImage = divLevel.appendChild(document.createElement("p")); rankImage.id = "rankImage" ico = rankImage.appendChild(document.createElement("img")); ico.src = rankImg; let rankLevel = divLevel.appendChild(document.createElement("p")); rankLevel.id = "rankLevel"; rankLevel.innerText = level; let rankExp = divLevel.appendChild(document.createElement("p")); rankExp.id = "rankExp"; let expBar = rankExp.appendChild(document.createElement("p")); expBar.id = "rankExpBar"; let expBarFill = rankExp.appendChild(document.createElement("p")); expBarFill.id = "rankExpBarFill"; if (level < expTable.length) { expBarFill.style.width = String(expRate) + "px"; } else { expBarFill.style.width = "100px"; } let expBarValue = rankExp.appendChild(document.createElement("p")); expBarValue.id = "rankExpBarValue"; if (level < expTable.length) { expBarValue.innerText=String(totalExp)+"/"+String(expTable[level]); } else { expBarValue.innerText = "Max Level"; expBarValue.style.color = "#fd9"; } } } function updateScroll() { if (LOGS) { console.log("%c[MLPF+]%c Updating UserNav...", CP, CN); } if (!navContainer) { return; } let menu = document.getElementsByClassName("userNavMenu"); let tip = document.getElementById("ipsTooltip"); let i; if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 100) { if (tip) { tip.style.position = "fixed"; tip.style.top = "32px"; } for (i=0; i < menu.length; i++) { if (!menu[i] || menu[i].style.display == "none") { continue; } menu[i].style.position = "fixed"; menu[i].style.top = "32px"; if (!navContainer.classList.contains("sticky")) { menu[i].style.display = "none"; } } if (!navContainer.classList.contains("sticky")) { document.body.appendChild(navContainer); navContainer.classList.add("sticky"); } } else { for (i=0; i < menu.length; i++) { if (!menu[i] || menu[i].style.display == "none") { continue; } if (navContainer.classList.contains("sticky")) { menu[i].style.display = "none"; } } if (navContainer.classList.contains("sticky")) { headerContainer.appendChild(navContainer); navContainer.classList.remove("sticky"); } } let rankBox = document.getElementById("divLevel"); if (rankBox) { let lastSep = document.querySelector(".lastExtraSep"); if(rankBox.getBoundingClientRect().left <= lastSep.getBoundingClientRect().right) { rankBox.style.visibility = "hidden"; } else { rankBox.style.visibility = ""; } } } /*======================================= // Post Nav =======================================*/ document.addEventListener("DOMContentLoaded", function() { setupPostNav(); }); function setupPostNav() { if (LOGS) { console.log("%c[MLPF+]%c Initializing Post List...", CP, CN); } if (document.body.getAttribute("data-pagecontroller") != "topic") { if (LOGS) { console.log("%c[MLPF+]%c Aborted Post List creation, the current page is not a topic", CP, CN); } return; } let postNav = document.querySelector("#postNav"); if (postNav == null) { postNav = document.createElement("div"); document.body.appendChild(postNav); postNav.id = "postNav"; } var ipsPagination = document.querySelector('.ipsPagination_pageJump'); if (ipsPagination) { let currPage = document.querySelector('.ipsPagination_page.ipsPagination_active').innerText; // Page Button let btn = postNav.appendChild(document.createElement("div")); btn.id = "postNavPage"; let a = btn.appendChild(document.createElement("a")); a.appendChild(document.createTextNode(ipsPagination.innerText)); let ico = a.appendChild(document.createElement("i")); ico.classList.add("fa", "fa-caret-down"); let box = postNav.appendChild(document.createElement("div")); box.id = "postNavPageForm"; box.classList.add("ipsMenu", "ipsMenu_normal", "ipsHide", "ipsMenu_bottomRight"); btn.onclick = function(){ box.classList.toggle("ipsHide") }; // Input Box let form = box.appendChild(document.querySelector('form[data-role="pageJump"]').cloneNode(true)); form.id = "postNavPageInput"; let pageInput = document.querySelector('#postNavPageInput ul li:first-of-type'); pageInput.id = "postNavPageInputField"; let inputContent = document.querySelector('#postNavPageInputField input'); inputContent.defaultValue = currPage; inputContent.onclick = function(){inputContent.value = ""}; // [-] pageInput.prepend(btn = document.createElement("p")); btn.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-caret-left"); btn.setAttribute("onclick", "this.nextElementSibling.stepDown()"); // [+] pageInput.append(btn = document.createElement("p")); btn.appendChild(ico = document.createElement("i")); ico.classList.add("fa", "fa-caret-right"); btn.setAttribute("onclick", "this.previousElementSibling.stepUp()"); } var postList = document.createElement("ul"); postNav.appendChild(postList); postList.id = "postNavList"; updatePostNav(); window.addEventListener('scroll', updatePostNav); if (LOGS) { console.log("%c[MLPF+]%c Post List initialized successfully", CP, CS); } } function updatePostNav() { if (LOGS) { console.log("%c[MLPF+]%c Updating Post List...", CP, CN); } var posts = document.querySelectorAll('.cPost'); var postNavItems = document.querySelectorAll('.postNavItem'); // Check For New Posts var postsCnt = posts.length; var itemsCnt = postNavItems.length; if (itemsCnt != postsCnt) { let diff = postsCnt - itemsCnt; if (LOGS) { console.log("%c[MLPF+]%c Posts on the list: "+itemsCnt+" / "+postsCnt, CP, CN); } if (LOGS) { console.log("%c[MLPF+]%c Fetching new "+diff+" posts to the list...", CP, CN); } let postList = document.querySelector('#postNavList'); let post, photo, name, eleName; for (let i=itemsCnt; diff>0; i++) { if (LOGS) { console.log("%c[MLPF+]%c Adding post #"+String(i+1), CP, CN); } posts[i].setAttribute("post-index", i); postList.appendChild(post = document.createElement("li")); post.classList.add("postNavItem"); post.setAttribute("index", i); post.addEventListener("click", function() { let post = document.querySelector('.cPost[post-index="' + String(i) + '"]'); let tgt = post.getBoundingClientRect().top - document.body.getBoundingClientRect().top - 100; window.scrollTo(0, tgt); }); if (posts[i].classList.contains("ipsComment_solved")) { post.classList.add("postNavSolution"); } // Draw User Photo post.appendChild(photo = document.createElement("img")); photo.src = posts[i].querySelector('.cAuthorPane_photo > .ipsUserPhoto > img').src; // Draw User Name post.appendChild(name = document.createElement("span")); eleName = posts[i].querySelector('.cAuthorPane_author a'); if (eleName == null) { eleName = posts[i].querySelector('.cAuthorPane_author'); } name.innerHTML = " " + eleName.innerHTML; diff--; } postNavItems = document.querySelectorAll('.postNavItem'); } postNavItems.forEach(function(item) { item.classList.remove("postNavModerated"); item.classList.remove("postNavSelected"); }); for (let i=0; i= ptop-100) && (wpos <= pbtm+50)) { postNavItems[i].classList.add("current"); done = true; } else { postNavItems[i].classList.remove("current"); } } // Check If The Page Changed if (posts[0].getAttribute("post-index") == null) { document.querySelector('#postNav').innerHTML = ""; setupPostNav(); } } /*======================================= // Other =======================================*/ document.addEventListener("DOMContentLoaded", function() { // Clickable Ranks document.querySelectorAll('[data-role="rank-image"]').forEach(function(item) { let img = item.innerHTML; item.innerHTML = '' + img + ''; }) // Footer Push let footer = document.getElementById("elCopyright"); if (footer) { footer.appendChild(document.createElement("br")); let pluginLink = footer.appendChild(document.createElement("a")); pluginLink.title = "MLPForums Plus Topic"; pluginLink.href = "https://mlpforums.com/topic/195950-mlpforums-plus/"; pluginLink.innerText = "Enhanced with MLPForums Plus plugin"; } if (LOGS) { console.log("%c[MLPF+]%c --- Finished loading MLPForums Plus ---", CP, "color:#f8b"); } });