// ==UserScript==
// @name SonicHackingContest Navbar Scroll
// @version 2020.12.24
// @description Avoids navbar dropdown menus from being cut-off and inaccessible by adding scrolling.
// @author Obsidian
// @namespace https://greasyfork.org/en/users/318252-obsidian
// @include /^https?://(www\.)?sonichacking\.org//
// @include /^https?://(www\.)?shc\.zone//
// @match http*://*.sonichacking.org/*
// @match http*://*.shc.zone/*
// @exclude /^https?://(www\.)?(shc\.zone|sonichacking\.org)/vault//
// @grant none
// @run-at document-end
// @icon data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAwUExURUdwTKfH4uzz+dfl8+70+nWn0hpqswpfrfD1+glfrXeo0v///wBbqxpstHCj0EWHwjcCEG0AAAALdFJOUwD49/Oay6syPmGDWhDOJgAABMNJREFUeNrtWtu2oyAMbUgVNRL+/28PoLa1AoRael7cD3NbM7O3uRO43S5cuHDhwoULFyQYhvsTw/Breq3oHQqdkN8pmEhZM3sYY6xlBlSrjB+p6AgXAU94IRBU3O8/UQBzDMYyBhHNLQHEcwKLiOYaMK3Ai/AacGicCmbOwQKRGpqmAuYVzIZVUwmpQHyT0NARkA2DTQLR/d/CYJEA7fwwlZ3gwYruzZxgJQraGWFUyswiI5C6N8oEFgmYDbZxg5aaILjhX00Q3DC0iAKQCpjtNxSEYQw93M/TpDWQESsw5/LRUavHBLb+Sikly8TToTgEcmC2ZvtiYywDFlvSVxQMSIRc8ak5BfVxcFek2MzfQb2CQRF+jT5EoqrzPdE36UM2VoSBo4fv0juA2AlDZYzLw0DIT/I628IJ9yafL3cCNvB+RSYMinhuBy6ZYCCyc0ugKvCrtvwz0z3Pb+bGyKXiL/hzqahVY/+XogB/wp9OBGiaf6+1ABP1D+bfIFEOFSEAsG0fhnM8DOExbwI0VgHpTJymCcLODVuKKNbjaerCKNwsKRJhuD/5TECkGvVF4Wg0dkhtWrN4OtTeDC0kSHywScDaBgmoFBZUA8nnY90pkhvBwHaK5LwPag4pI4iHRPtyo5AtrHWLG90J3WB3lxn8JR949LLN4NuNis0ORsvtT9g3lBfsA1K5VRl8v89Jizbvf3X4wkENDjdKGSdYtsaYbeHA2XF9kKWBOfATVrSH7OezrL4eYb4gQHpQixig4oiZzgrxQY1jAqRDliE4fVCDMwKAphS/uA/E+KVRaAn0LT4nivmjIUBKusccz/KfEgDUJeK/4qBgj+Y3s0Ehv46fFGsOCgcLhBUbi/ghwV+3qInGv+B2LcV/Q6obxTBWgYo1xCDF7e8MUHlShDf/L3OHKQ4wCf6bql0VcKQHmIIVmSjFP1UflU2kBXBeAJDqUy1A1e9K8DCImHwhAYIxfTVavyvgiAGOAszz3iPDX50Cu4nwxQAHAaxI8SZvSo/BHy0reN8Cw4jIB/5NlFFKn70aTkQBv+jhyLHBZBvAsi7DT/i3RDAv9oCjwrVGpgrgpyH40pHgpS7BgX+JECY15i7nPz0Q83outBiZSOB5WslVgE9D8CXK4nOxfQSIQcI++z4iE4LGWHawNrFDej8ewT5AeHnm0/X55xHR/9swAL49pYPIxRrv/xJY5kcCcBAI/Zg9C0c84MjVsjzrPPrwI4Q/i8SrsQygdn542B+py9NHPGAYiQgdbz+Oo35gHPu+S5f78OBv0x0MZkP2j+UHKjuzepcRePJY3uq+1LYeLWLhhyK/3r1MYCRKsi+rg9Lywj5nFAn/rgr51pFlX2xQqFu8roz8+FXmv3UPp670umSyvnR8h7A08+OXgP+G9Eo/askCBwpLsa34SfjXEGAk1Yn+wbJTVYSFSGBmkOzGQhWwVfTBDR0JXhsA0SCIQYtEVfTBCL4kEMSee7zIsuX785HUB/TeCE4CLPUZ2PoN1FKJYBei5T25/ox+dYQrjfDeDxGfa38reMbRf0q/GNCVZy9jg/9NWPsjMAOS6sufcf6hm28TK7ReA2SZhrpTX3fq6Vm/4L/4V8Po24ULFy5cuHDhQhp/KJVML/pyu60AAAAASUVORK5CYII=
// @noframes
// ==/UserScript==
/* jshint esversion: 6 */
(function(){
'use strict';
function GM_addStyle(aCss){
var head = document.getElementsByTagName('head')[0];
if(head){
var style = document.createElement('style');
style.setAttribute('type', 'text/css');
style.textContent = aCss;
head.appendChild(style);
return style;
}
return null;
}
var strCss = `
@media (min-width: 992px) {
.navbar-nav .dropdown-menu {
max-height: calc(100vh - 100% - 2px);
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: rgba(255,255,255,0.38) rgba(32,32,32,0.35);
overscroll-behavior: contain;
}
}
/* mobile style (max-width: 991.999) */
@media not all and (min-width: 992px) {
.navbar-collapse {
padding-top: 0.7px;
}
.navbar-collapse .navbar-nav {
max-height: calc(100vh - 54px);
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: rgba(255,255,255,0.38) rgba(32,32,32,0.35);
overscroll-behavior: contain;
min-width: max-content;
max-width: 100vw;
width: 24em;
}
.navbar {
max-height: 50.6px;
/*max-height: calc(3rem + 2px);*/
}
#entry_banner_image {
width: 100%;
max-width: 352px;
}
.shc-news-body iframe {
max-width: 100%;
max-height: calc((100vw - 4rem - 2px) * 0.5625); /* assume this is a 16x9 video */
}
.shc-news-body img {
max-width: 100%;
height: auto;
}
}
/* constrain size of news post avatars on narrow screens */
@media only screen and (max-width: 480px) {
.shc-news-header h2 {
margin-right: 0px !important;
font-size: 1.5rem;
}
.shc-news-header h2 a {
font-size: 1.5rem;
}
.shc-news-header img {
top: auto;
bottom: -0.5em;
right: 0.4rem;
height: auto !important;
width: 56px;
width: 3.8rem;
}
/* trick for padding end of last-line */
.shc-news-header h2::after {
content: "\\00a0";
display: inline;
visibility: hidden;
margin-left: -0.25em;
padding-right: 54px;
padding-right: calc(3.7rem - 1px);
}
}
/* styles for all */
.navbar-nav > .nav-divider {
flex-shrink: 0;
}
.navbar-nav > .nav-divider:first-child {
display: none;
}
.navbar-backdrop {
top: 50.4px !important;
/*top: calc(3rem + 1px) !important;*/
}
.bg-shc-tails-light {
background-color: #edd090 !important;
background-color: var(--shc-tails-light, #edd090) !important;
}
.bg-shc-knuckles-light {
background-color: #e0c0c6 !important;
background-color: var(--shc-knuckles-light, #e0c0c6) !important;
}
/**/
.bg-shc-tails-light img[src*=\\/res\\/img\\/title] {
filter: hue-rotate(calc(39deg - 207deg)) brightness(1.6);
}
.bg-shc-knuckles-light img[src*=\\/res\\/img\\/title] {
filter: hue-rotate(calc(349deg - 207deg)) contrast(1.08);
}
/**/
/* non-standard thin scrollbar style */
.navbar-nav .dropdown-menu::-webkit-scrollbar,
.navbar-collapse .navbar-nav::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.navbar-nav .dropdown-menu::-webkit-scrollbar-track,
.navbar-collapse .navbar-nav::-webkit-scrollbar-track {
background: rgba(32,32,32,0.35);
}
.navbar-nav .dropdown-menu::-webkit-scrollbar-track {
margin: 0 1px 1px 1px; /* push away from menu border */
}
.navbar-nav .dropdown-menu::-webkit-scrollbar-thumb,
.navbar-collapse .navbar-nav::-webkit-scrollbar-thumb {
background: transparent linear-gradient(to right, rgba(248,248,248,0.35) 0%, rgba(248,248,248,0.35) 100%) 1.1px 0px/6.2px repeat-y;
}
.navbar-nav .dropdown-menu::-webkit-scrollbar-thumb:hover,
.navbar-collapse .navbar-nav::-webkit-scrollbar-thumb:hover {
background-image: linear-gradient(to right, rgba(208,208,208,0.35) 0%, rgba(208,208,208,0.35) 100%);
}
.navbar-nav .dropdown-menu::-webkit-scrollbar-thumb:active,
.navbar-collapse .navbar-nav::-webkit-scrollbar-thumb:active {
background-image: linear-gradient(to right, rgba(152,152,152,0.35) 0%, rgba(152,152,152,0.35) 100%);
}
.navbar-nav .dropdown-menu::-webkit-scrollbar-thumb:horizontal,
.navbar-collapse .navbar-nav::-webkit-scrollbar-thumb:horizontal {
background-repeat: repeat-x;
background-position: 0px 1.1px;
background-size: auto 6.15px;
}
.navbar-nav .dropdown-menu::-webkit-scrollbar-corner,
.navbar-collapse .navbar-nav::-webkit-scrollbar-corner {
background: transparent;
}`;
// Insert CSS styles
GM_addStyle(strCss);
// Add background color to menus
var bgTheme = document.querySelector(".navbar").className.match(/(bg-shc-[a-z]+)|$/)[1] || "bg-shc-sonic";
[].forEach.call(document.querySelectorAll(".navbar .navbar-nav"), function(navnode){navnode.classList.add(bgTheme);});
// Trigger backdrop event when clicking empty menu area
[].forEach.call(document.querySelectorAll(".navbar .navbar-collapse"), function(navnode){
navnode.addEventListener("click", function(event){if(event.target===navnode){document.querySelector(".navbar-backdrop").click();}});
});
// Reset menu scroll position back to top
[].forEach.call(document.querySelectorAll(".navbar .nav-link.dropdown-toggle"), function(ddnode){
ddnode.addEventListener("click", function(){setTimeout(function(){ddnode.parentElement.querySelector(".dropdown-menu").scrollTop=0;},100);});
});
// Reset mobile-view menu scroll position back to top
[].forEach.call(document.querySelectorAll(".navbar-toggler"), function(hbnode){
hbnode.addEventListener("click", function(event){
var n = document.querySelector(event.currentTarget.dataset.target);
setTimeout(function(){n.scrollTop=0; if(!!n.firstElementChild){n.firstElementChild.scrollTop=0;}},80);
});
});
// BONUS: Switching Color Themes
// Function for applying a theme
var cycleThemes = function(newTheme){
var themes = ["shc-sonic","shc-tails","shc-knuckles"];
var theme = document.querySelector(".navbar").className.match(/bg-(shc-[a-z]+)(?!\S)|$/)[1];
var themeIndex = themes.indexOf(theme);
var themeNext = newTheme || themes[(themeIndex+1)%themes.length];
if(!theme){theme = themes[0];}
if(theme===themeNext || !(/^shc-[a-z]+$/).test(themeNext)){return theme;}
var themeExp = new RegExp("(bg-|border-|btn-)("+theme+")","g");
[].forEach.call(document.querySelectorAll(".bg-"+theme+", .border-"+theme+", .btn-"+theme), function(node){
node.className = node.className.replace(themeExp, "$1"+themeNext);
});
window.hapi_c.MODAL_THEME = window.hapi_c.MODAL_THEME.replace(/bg-shc-[a-z]+/, "bg-"+themeNext);
// Some elements (footer, schedule, shc-entry-tags) are using CSS Var for color rather than class name.
// Modify CSS Var "--shc-sonic" to match new theme:
var cloneCssVar = function(fromVar, toVar, newOnly){
if(!!getComputedStyle(document.documentElement).getPropertyValue("--"+fromVar)){
if(!newOnly || !getComputedStyle(document.documentElement).getPropertyValue("--"+toVar)){
document.documentElement.style.setProperty("--"+toVar, getComputedStyle(document.documentElement).getPropertyValue("--"+fromVar));
return true;
}
}
return false;
};
cloneCssVar("shc-sonic","shc-sonic-backup",true);
if(themeNext==="shc-sonic"){
cloneCssVar("shc-sonic-backup","shc-sonic");
}else{
cloneCssVar(themeNext,"shc-sonic");
}
// Set body background tint
if(!document.querySelector(".alert")){
document.body.className = document.body.className.replace(/(?:^|\s)bg-(shc-[a-z]+)-light(?!\S)/g, "").replace(/^\s/, "");
document.body.classList.add("bg-"+themeNext+"-light");
}
return themeNext;
};
window.cycleThemes = cycleThemes;
// Insert a button for selecting theme
var strHtml = `<div id="theme-selector" class="dropup" style="position:absolute;display:inline-block;right:1em;margin-top:-2px;">
<a id="theme-button" class="dropdown-toggle btn btn-shc-sonic" href="#" role="button" data-toggle="dropdown" style="display:block;padding:0 4px;font-size:1.1em;border:1px solid rgba(255,255,255,.4);">Theme</a>
<ul role="menu" class="dropdown-menu dropdown-menu-right dropdown-pills dropdown-dark bg-shc-sonic" style="min-width:auto;">
<li><a class="dropdown-item" role="menuitem" href="#">SHC-Sonic</a></li>
<li><a class="dropdown-item" role="menuitem" href="#">SHC-Tails</a></li>
<li><a class="dropdown-item" role="menuitem" href="#">SHC-Knuckles</a></li>
</ul>
</div>`;
var footer = document.getElementsByTagName("footer")[0];
footer.insertAdjacentHTML("afterbegin", strHtml);
[].forEach.call(footer.querySelectorAll("#theme-selector a.dropdown-item"), function(node){
node.addEventListener("click", function(event){
var res=cycleThemes(event.currentTarget.innerText.toLowerCase()); event.preventDefault(); sessionStorage.setItem("theme",res); return false;
}, false);
});
// Restore last theme
var savedTheme = sessionStorage.getItem("theme");
if(!!savedTheme){cycleThemes(savedTheme);}
})();