// ==UserScript==
// @name BrainTools: Custom Menu Links
// @namespace brainslug.torn.utility
// @version 0.3.2
// @description Inject custom menu links inspired by torntools
// @author Brainslug [2323221]
// @match https://www.torn.com/*
// @icon https://www.google.com/s2/favicons?domain=torn.com
// @downloadURL https://raw.githubusercontent.com/br41nslug/torn-brainscripts/main/scripts/custom-menu-links.user.js
// @updateURL https://raw.githubusercontent.com/br41nslug/torn-brainscripts/main/scripts/custom-menu-links.user.js
// @grant GM_addStyle
// ==/UserScript==
/**
* This list configures which items will be added to the menu.
* An item may contain the following settings:
* label: This is the text in the link
* after/before: Where the link will be inserted (available choices below)
* target: The page you are linking to. For torn pages only the "/bazaar.php" part is needed but for external pages you need the full "https://example.com" domain.
* icon: For lack of a better solution yet this is plain html to be injected. The icons i used here with the exception of the bazaar were taken from the city map list.
* newTab: true/false defaults to false, whether to open a new tab when you click the link
*/
const customLinks = [
{ label: "Raceway", after: "home", target: "/page.php?sid=racing", icon: '' },
{ label: "Item Market", before: "items", target: "/imarket.php", icon: '' },
{ label: "Bazaar", after: "items", target: "/bazaar.php#/manage", icon: '' },
{ label: "Pharmacy", before: "city", target: "/shops.php?step=pharmacy", icon: '' },
{ label: "Travel Agency", after: "hall_of_fame", target: "/travelagency.php", icon: '' },
];
/**
* Torn Menu Items:
* - home
* - items
* - city
* - job
* - gym
* - properties
* - education
* - crimes
* - missions
* - newspaper
* - jail
* - hospital
* - casino
* - forums
* - hall_of_fame
* - my_faction
* - recruit_citizens
* - competitions
*/
const tag = tagName => (attrs={}) => {
const elem = document.createElement(tagName);
if ( !! attrs.text) elem.innerText = attrs.text;
if ( !! attrs.html) elem.innerHTML = attrs.html;
if (tagName == 'a') {
if ( !! attrs.href) elem.href = attrs.href;
if ( !! attrs.target) elem.target = attrs.target;
}
if ( !! attrs.cls) {
if (Array.isArray(attrs.cls)) attrs.cls.forEach(c => elem.classList.add(c));
else elem.classList.add(attrs.cls);
}
if ( !! attrs.children) attrs.children.forEach(child => elem.append(child));
return elem;
};
const watchNav = (linkname, timeout=50, retries=50) => new Promise((resolve, reject) => {
let count = 0;
const interval = setInterval(() => {
const $elem = unsafeWindow.document['querySelector']('#nav-'+linkname);
if ( !! $elem) {
clearInterval(interval);
return resolve($elem);
}
if (count >= retries) {
clearInterval(interval);
console.error(`Max retries(${retries}) reached for "#nav-${linkname}"!`);
return reject();
}
count++;
}, timeout);
});
const findClass = (cls, elem) => {
let result = '';
elem.classList.forEach(className => cls.test(className) && (result = className));
if (result === '') console.error('[BrainTools]', 'class not found!', cls, elem);
return result;
};
const injectLink = (link, elem) => elem.parentNode.insertBefore(tag`div`({
cls: ['brain-link', findClass(/^area-desktop_/, elem)],
children: [tag`div`({
cls: findClass(/^area-row_/, elem.children[0]),
children: [tag`a`({
cls: findClass(/^desktopLink_/, elem.children[0].children[0]),
href: link.target,
target: !! link.newTab ? '_blank' : '_self',
children: [
tag`span`({
cls: 'icon',
html: link.icon || '',
}),
tag`span`({
cls: findClass(/^linkName_/, elem.children[0].children[0].children[1]),
text: link.label,
}),
]
})]
})]
}), !! link.before ? elem : elem.nextSibling);
// inject links
customLinks.forEach(link => {
if ((! link.before && ! link.after) || ! link.target || ! link.label)
return console.error('[BrainTools]', 'Bad link configured', link);
const selector = !! link.before ? link.before : link.after;
watchNav(selector).then(element => {
console.info('[BrainTools]', 'Injecting custom link', link.label, link.target);
injectLink(link, element);
});
});
// inject styles
GM_addStyle(`
.brain-link a .icon {
float: left;
width: 34px;
height: 23px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
margin-left: 0;
}
`);