Skip to content

Instantly share code, notes, and snippets.

@ephphatha
Created November 20, 2019 12:41
Show Gist options
  • Save ephphatha/e661e01d42134573bdcd5b1bbabb7988 to your computer and use it in GitHub Desktop.
Save ephphatha/e661e01d42134573bdcd5b1bbabb7988 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Baseball Tips Tracker
// @namespace https://thelettereph.com/
// @version 1.0
// @description Tracks baseball earnings and owed tips in OBL
// @author ephphatha
// @match *://politicsandwar.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
class NationStats {
constructor() {
this.allNationStats = new Map(JSON.parse(localStorage.getItem('f-goons-paw-nations')));
}
save() {
localStorage.setItem('f-goons-paw-nations', JSON.stringify([...this.allNationStats]));
return true;
}
get(id, createMissing = true) {
id = parseInt(id);
if (!isNaN(id)) {
if (!this.allNationStats.has(id) && createMissing) {
this.allNationStats.set(id, {id: id, revenue: 0});
}
return this.allNationStats.get(id);
}
}
set(id, nation) {
id = parseInt(id);
if (!isNaN(id)) {
this.allNationStats.set(id, nation);
return this.save();
}
return false;
}
updateRevenue(id, delta) {
const nation = this.get(id);
nation.revenue = (nation.revenue || 0) + parseFloat(delta);
nation.balance = nation.revenue * 0.3 - (nation.income || 0);
this.save();
}
updateIncome(id, delta) {
const nation = this.get(id);
nation.income = (nation.income || 0) + parseFloat(delta);
nation.balance = (nation.revenue || 0) * 0.3 - nation.income;
this.save();
}
clearRevenue(id) {
const nation = this.get(id);
nation.revenue = 0;
delete nation.income;
delete nation.balance;
this.save();
}
list(orderBy = null, defaultDir = true) {
if (!orderBy) {
return [...this.allNationStats.values()];
} else {
return [...this.allNationStats.values()].sort((a, b) => {
if (defaultDir) {
return compare(a[orderBy], b[orderBy]);
} else {
return compare(b[orderBy], a[orderBy]);
}
});
}
}
baseList(balanceThreshold = 1) {
return this.list('revenue').filter(nation => (typeof nation.balance !== "undefined" ? nation.balance : (nation.revenue * 0.3)) >= balanceThreshold);
}
}
class ControlVariables {
constructor() {
this.controlVars = new Map(JSON.parse(localStorage.getItem('f-goons-paw-controls')));
}
save() {
localStorage.setItem('f-goons-paw-controls', JSON.stringify([...this.controlVars]));
return true;
}
get(key) {
return this.controlVars.get(key);
}
set(key, value) {
this.controlVars.set(key, value);
return this.save();
}
}
const nationStats = new NationStats();
const controlVariables = new ControlVariables();
function compare(a, b) {
if (typeof a === 'number' && typeof b === 'number') {
return b - a;
} else {
return a > b ? 1 : a < b ? -1 : 0;
}
}
function createChildElement(tag, parent) {
const element = document.createElement(tag);
parent.appendChild(element);
return element;
}
function addTextToElement(element, text) {
const textNode = document.createTextNode(text);
element.appendChild(textNode);
}
function createTab(parent, name, text) {
const tab = createChildElement('li', parent);
tab.id = "f-goons-paw-tab-" + name;
const tabLink = createChildElement('a', tab);
tabLink.href = "#";
tabLink.innerText = text;
tabLink.dataset.tabName = name;
return tab;
}
function clearChildren(node) {
const clearedNode = node.cloneNode(false);
node.parentNode.replaceChild(clearedNode, node);
return clearedNode;
}
function renderControlPanel() {
const helperStyle = document.createElement('style');
helperStyle.type = 'text/css';
helperStyle.id = 'paw-goons';
helperStyle.innerText = '#f-goons-paw-main {position:fixed; right:0; bottom:0;}' +
'#f-goons-paw-main ul.nav {background:#ddd; border-top-left-radius:4px;}' +
'#f-goons-paw-container {border-left:1px solid #ddd; background:white; overflow:auto;}';
document.head.appendChild(helperStyle);
const mainDiv = document.createElement('div');
mainDiv.id = 'f-goons-paw-main';
// render tabs
const mainNav = createChildElement('ul', mainDiv);
mainNav.className = 'nav nav-tabs';
const baseballTab = createTab(mainNav, 'baseball', '⚾');
const minMaxTab = createTab(mainNav, 'min-max', '🗕');
minMaxTab.style = 'float: right;';
mainNav.addEventListener('click', handleTabClick);
// panel container
const panel = createChildElement('div', mainDiv);
panel.id = 'f-goons-paw-container';
panel.style = 'max-height: ' + window.innerHeight * 0.6 + 'px;';
renderActivePanel(mainDiv);
document.body.appendChild(mainDiv);
}
function renderActivePanel(context) {
if (!context) {
context = document.querySelector('#f-goons-paw-main');
}
context.querySelectorAll('.nav li.active').forEach( it => { it.className = '' } );
const minimised = controlVariables.get('minimised');
const minMaxTab = context.querySelector('#f-goons-paw-tab-min-max');
const panel = context.querySelector('#f-goons-paw-container');
if (minimised) {
//panel is minimised
minMaxTab.firstElementChild.innerText = '🗖';
clearChildren(panel);
} else {
minMaxTab.firstElementChild.innerText = '🗕';
const activeTabElement = context.querySelector('#f-goons-paw-tab-baseball');
activeTabElement.className = 'active';
renderRevenueTable(panel);
}
}
function renderRevenueTable(parent) {
const table = document.createElement('table');
table.className = 'nationtable';
const thead = createChildElement('thead', table);
let tr = createChildElement('tr', thead);
for (const text of ['Nation', 'Revenue', 'Tips Owed', 'Tips Received']) {
const th = createChildElement('th', tr);
th.innerText = text;
}
const tbody = createChildElement('tbody', table);
const numberFormat = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' });
for (const nation of nationStats.baseList()) {
tr = createChildElement('tr', tbody);
let td = createChildElement('td', tr);
const nationLink = createChildElement('a', td);
nationLink.innerText = nation.name || nation.id;
nationLink.href = "https://politicsandwar.com/nation/id=" + nation.id;
td = createChildElement('td', tr);
td.className = 'right';
addTextToElement(td, numberFormat.format(nation.revenue) + ' ');
const clearLink = createChildElement('a', td);
clearLink.innerText = '(clear)';
clearLink.dataset.nationId = nation.id;
clearLink.addEventListener('click', handleClearClick);
td = createChildElement('td', tr);
td.className = 'right';
addTextToElement(td, numberFormat.format((typeof nation.balance !== "undefined" ? nation.balance : (nation.revenue * 0.3))));
td = createChildElement('td', tr);
const tipInput = createChildElement('input', td);
tipInput.type = 'number';
tipInput.dataset.nationId = nation.id;
}
table.addEventListener('change', handleIncomeChange);
parent = clearChildren(parent);
parent.appendChild(table);
}
function handleTabClick(event) {
if (event.target.tagName == 'A') {
const tabName = event.target.dataset.tabName;
if (tabName == 'min-max') {
controlVariables.set('minimised', !controlVariables.get('minimised'));
} else {
controlVariables.set('minimised', false);
}
renderActivePanel();
}
}
function handleClearClick(event) {
nationStats.clearRevenue(event.target.dataset.nationId);
event.target.parentNode.parentNode.remove();
}
function handleIncomeChange(event) {
nationStats.updateIncome(event.target.dataset.nationId, event.target.value);
event.target.value = null;
const numberFormat = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' })
const nation = nationStats.get(event.target.dataset.nationId);
event.target.parentNode.previousSibling.innerText = numberFormat.format((typeof nation.balance !== "undefined" ? nation.balance : (nation.revenue * 0.3)));
}
if (window.location.pathname.startsWith('/obl/play')) {
// Look for a table cell that contains the text "Game Results", this indicates we're on the results screen of an away game (most likely)
const gameResultsHeader = document.evaluate('.//th[text()="Game Results"]', document.body, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
if (gameResultsHeader) {
const gameResultsTable = gameResultsHeader.parentNode.parentNode; // Up two levels is the table itself
const hostNationLink = gameResultsTable.querySelector('tr:nth-child(3) td:nth-child(2) a'); // Second cell of the third row has the host nation link
const hostNation = nationStats.get(hostNationLink.href.split('id=')[1]); // grab the ID from the end of the url
hostNation.name = hostNationLink.innerText;
// Fifth row has the scores
const awayScore = parseInt(gameResultsTable.querySelector('tr:nth-child(5) td:nth-child(2)').textContent);
const homeScore = parseInt(gameResultsTable.querySelector('tr:nth-child(5) td:nth-child(3)').textContent);
// Seventh row has the revenue (fourth cell)
let homeTeamRevenue = parseFloat(gameResultsTable.querySelector('tr:nth-child(7) td:nth-child(4)').textContent.substr(1).replace(',',''));
// If the home team won also include the game winnings (second cell)
if (homeScore >= awayScore) {
homeTeamRevenue += parseFloat(gameResultsTable.querySelector('tr:nth-child(7) td:nth-child(2)').textContent.substr(1).replace(',',''))
}
// Just keep track of the total so far.
nationStats.updateRevenue(hostNation.id, homeTeamRevenue); // this method performs a save so it'll also persist the name change above.
}
}
renderControlPanel();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment