// ==UserScript==
// @name Yahoo Fantasy Baseball
// @namespace http://robobruin.com/greasemonkey/fantasysports
// @description Live baseball fantasy scoring
// @include http://baseball.fantasysports.yahoo.com/*
//
// --------------------------------------------------------------------
// This is a Greasemonkey user script.
// It provides live scoring updates for Yahoo Fantasy Baseball leagues.
//
// --------------------------------------------------------------------
// This script is released under Mozilla Public License 1.1
// http://www.mozilla.org/MPL/
//
// To install, you need Greasemonkey:
// http://greasemonkey.mozdev.org/
//
// Then restart Firefox and revisit this script:
// http://userscripts.org/scripts/show/5143
//
// Under Tools, there will be a new menu item to "Install User Script".
// Accept the default configuration and install.
//
// To uninstall, go to Tools/Manage User Scripts,
// select "Yahoo Fantasy Baseball", and click Uninstall.
//
// --------------------------------------------------------------------
// For code enhancements, feature requests, or to report bugs, visit:
// http://code.google.com/p/freebiestats/issues/list
//
// --------------------------------------------------------------------
// Credits for modal dialog inspiration:
// http://gabrito.com/files/subModal/
// http://www.sitening.com/blog/2006/03/29/create-a-modal-dialog-using-css-and-javascript/
//
// --------------------------------------------------------------------
const VERSION = "2.4.2";
const SCRIPT_URL = 'http://userscripts.org/scripts/source/5143.user.js';
(function () {
const YAHOO_MLB_BASEURL = 'http://baseball.fantasysports.yahoo.com';
const BUTTON_LABEL = 'Show Freebie Stats!';
const HIDDEN_DIV_ID = 'robobruinDiv';
const MODAL_DIV_ID = 'robobruinModal';
const STAT_BODY_ID = 'robobruinTableBody';
const STAT_BUTTON_ID = 'robobruinStatBtn';
const BATTER = 'batter';
const PITCHER = 'pitcher';
const TOTALER = 'total';
const TEAM = 'team';
const LEAGUE = 'league';
/* run in team mode, league mode, or don't run at all */
var SCRIPT_MODE = null;
if (location.href.match(/^http\:\/\/baseball\.fantasysports\.yahoo\.com\/b\d\/\d+\/(team\?mid=)?\d+.*/i)) {
if (location.href.indexOf('positioncaps') != -1) return;
SCRIPT_MODE = TEAM;
}
/*
else if (location.href.match(/^http\:\/\/baseball\.fantasysports\.yahoo\.com\/b\d\/\d+.$/i)) {
SCRIPT_MODE = LEAGUE;
}
*/
else return;
/**********************************************************************************************/
/* all players */
function Player() {
this._playerId = '';
this._name = '';
this._displayName = '';
this._position = '';
this._gameinfo = '';
this._order = 0;
this._h = 0;
this._bb = 0;
this._isBatter = null;
}
Player.prototype.playerId = function (arg) {if (arguments.length) this._playerId = arg; else return this._playerId;}
Player.prototype.name = function (arg) {if (arguments.length) this._name = arg; else return this._name;}
Player.prototype.displayName = function (arg) {if (arguments.length) this._displayName = arg; else return this._displayName;}
Player.prototype.position = function (arg) {if (arguments.length) this._position = arg; else return this._position;}
Player.prototype.gameinfo = function (arg) {if (arguments.length) this._gameinfo = arg; else return this._gameinfo;}
Player.prototype.order = function (arg) {if (arguments.length) this._order = parseInt(arg); else return this._order;}
Player.prototype.isOnBench = function () {return (this._position == 'BN' || this._position == 'DL');}
Player.prototype.isBatter = function () {return this._isBatter;}
Player.prototype.h = function (arg) {if (arguments.length) this._h = parseInt(arg); else return this._h;}
Player.prototype.bb = function (arg) {if (arguments.length) this._bb = parseInt(arg); else return this._bb;}
function Batter() {
this._ab = 0;
this._r = 0;
this._h2b = 0; // doubles
this._h3b = 0; // triples
this._hr = 0;
this._rbi = 0;
this._sb = 0;
this._sf = 0;
this._hbp = 0; // hit by pitch
this._isBatter = true;
}
/* batters */
Batter.prototype = new Player();
Batter.prototype.ab = function (arg) {if (arguments.length) this._ab = parseInt(arg); else return this._ab;}
Batter.prototype.r = function (arg) {if (arguments.length) this._r = parseInt(arg); else return this._r;}
Batter.prototype.h2b = function (arg) {if (arguments.length) this._h2b = parseInt(arg); else return this._h2b;}
Batter.prototype.h3b = function (arg) {if (arguments.length) this._h3b = parseInt(arg); else return this._h3b;}
Batter.prototype.hr = function (arg) {if (arguments.length) this._hr = parseInt(arg); else return this._hr;}
Batter.prototype.rbi = function (arg) {if (arguments.length) this._rbi = parseInt(arg); else return this._rbi;}
Batter.prototype.sb = function (arg) {if (arguments.length) this._sb = parseInt(arg); else return this._sb}
Batter.prototype.sf = function (arg) {if (arguments.length) this._sf = parseInt(arg); else return this._sf}
Batter.prototype.hbp = function (arg) {if (arguments.length) this._hbp = parseInt(arg); else return this._hbp;}
Batter.prototype.avg = function () {
if (this._ab > 0) {
var avg = (this._h / this._ab).toFixed(3);
avg = (new String(avg).charAt(0) != '1') ? (avg.substring(1, avg.length)) : avg;
return avg;
}
else return '-';
}
Batter.prototype.obp = function () {
if ((this._ab + this._bb + this._hbp + this._sf) > 0) {
var obp = ((this._h + this._bb + this._hbp) / (this._ab + this._bb + this._hbp + this._sf)).toFixed(3);
obp = (new String(obp).charAt(0) != '1') ? (obp.substring(1, obp.length)) : obp;
return obp;
}
else return '-';
}
/* slugging percentage */
Batter.prototype.slg = function () {
if (this._ab > 0) {
var h1b = this._h - this._hr - this._h2b - this._h3b;
var slg = ((h1b + (this._h2b * 2) + (this._h3b * 3) + (this._hr * 4)) / this._ab).toFixed(3);
slg = (new String(slg).charAt(0) == '0') ? (slg.substring(1, slg.length)) : slg;
return slg;
}
else return '-';
}
/* on base plus slugging percentage */
Batter.prototype.ops = function () {
var obp = this.obp();
var slg = this.slg();
if (obp == '-') {
return slg;
}
else if (slg == '-') {
return obp;
}
else {
var ops = (parseFloat(obp) + parseFloat(slg)).toFixed(3);
ops = (new String(ops).charAt(0) == '0') ? (ops.substring(1, ops.length)) : ops;
return ops;
}
}
Batter.prototype.hab = function () {
return this._h + '/' + this._ab;
}
Batter.prototype.add = function (player) {
this._ab += player.ab();
this._h += player.h();
this._bb += player.bb();
this._r += player.r();
this._h2b += player.h2b();
this._h3b += player.h3b();
this._hr += player.hr();
this._rbi += player.rbi();
this._sb += player.sb();
this._sf += player.sf();
this._hbp += player.hbp();
}
/* pitchers */
function Pitcher() {
//this._displayIP = '-';
/* keep track of full IP and partial IP
* from which the IP is calculated
*/
this._fullIP = 0;
this._partIP = 0;
this._er = 0;
this._k = 0;
this._w = 0;
this._l = 0;
this._s = 0;
this._isBatter = false;
}
Pitcher.prototype = new Player();
Pitcher.prototype.IP = function (arg) {
if (arguments.length) {
this._fullIP += parseInt(arg);
this._partIP += (arg * 10) % 10;
}
else {
return ((this._fullIP + parseInt(this._partIP / 3)) + '.' + (this._partIP % 3));
}
}
Pitcher.prototype.er = function (arg) {if (arguments.length) this._er = parseInt(arg); else return this._er;}
Pitcher.prototype.w = function (arg) {if (arguments.length) this._w = parseInt(arg); else return this._w;}
Pitcher.prototype.l = function (arg) {if (arguments.length) this._l = parseInt(arg); else return this._l;}
Pitcher.prototype.s = function (arg) {if (arguments.length) this._s = parseInt(arg); else return this._s;}
Pitcher.prototype.k = function (arg) {if (arguments.length) this._k = parseInt(arg); else return this._k;}
/* ip() is used to calculate era and whip */
Pitcher.prototype.ip = function () {
/* calculate IP from raw full and partial IP stats */
var ip = this._fullIP + (this._partIP / 3);
return ip;
}
Pitcher.prototype.era = function () {
var ip = this.ip();
if (ip != 0) {
var era = this._er * 9 / ip;
return era.toFixed(2);
}
else return '-';
}
Pitcher.prototype.whip = function () {
var ip = this.ip();
if (ip != 0) {
var whip = (this._bb + this._h) / ip;
return whip.toFixed(2);
}
else return '-';
}
Pitcher.prototype.add = function (player) {
this._fullIP += player._fullIP;
this._partIP += player._partIP;
this._h += player.h();
this._bb += player.bb();
this._er += player.er();
this._w += player.w();
this._l += player.l();
this._s += player.s();
this._k += player.k();
}
function TotalBatter(label, order) {
this._position = TOTALER;
if (arguments.length) {
this._displayName = label;
this._order = order;
}
else {
this._displayName = 'total';
this._order = 0;
}
}
function TotalPitcher(label, order) {
this._position = TOTALER;
if (arguments.length) {
this._displayName = label;
this._order = order;
}
else {
this._displayName = 'total';
this._order = 0;
}
}
TotalBatter.prototype = new Batter();
TotalPitcher.prototype = new Pitcher();
/**********************************************************************************************/
/**********************************************************************************************/
/**
Setup the modal window
@date replace refresh button with date if date is not null
@return no return value
*/
function setUpModal(date) {
if (document.getElementById(MODAL_DIV_ID)) {
document.body.removeChild(document.getElementById(MODAL_DIV_ID));
}
var div = document.createElement("div");
div.appendChild(document.createElement("div"));
document.body.appendChild(div);
div.id = MODAL_DIV_ID;
/* remove the background image since the auto-scrolling is now
* disabled to get around continous auto scrolling in a short
* browser window; change table baground to a light tint instead
*/
GM_addStyle('#' + MODAL_DIV_ID + " {text-align:center;position:absolute;left: 0px;top: 0px;width:100%;height:100%;text-align:center;z-index: 200;}");//background: url(\"data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%002%00%00%002%01%03%00%00%00%24%F1%1A%F2%00%00%00%06PLTE%9D%BF%C4%FF%FF%FFo%99%7C%D4%00%00%00%02tRNS%FF%00%E5%B70J%00%00%00%01bKGD%01%FF%02-%DE%00%00%00%09pHYs%00%00%00H%00%00%00H%00F%C9k%3E%00%00%00yIDATx%01%05%C1%01%01%00%00%08%02%20%1C%D9I%07u%A2%13A%06%5C%0A6%03.%05%9B%01%97%82%CD%80K%C1f%C0%A5%603%E0R%B0%19p)%D8%0C%B8%14l%06%5C%0A6%03.%05%9B%01%97%82%CD%80K%C1f%C0%A5%603%E0R%B0%19p)%D8%0C%B8%14l%06%5C%0A6%03.%05%9B%01%97%82%CD%80K%C1f%C0%A5%603%E0R%B0%19p)%D8%0C%B8%14l%06%5C%0A%F6%01%90%ADD%F3%BDe%02%17%00%00%00%00IEND%AEB%60%82\");}");
//GM_addStyle('#' + MODAL_DIV_ID + ' div {width:500px;margin:100px auto;background-color:#fff;border:1px solid #000;padding:15px;text-align:center;z-index:201;}');
GM_addStyle('#' + MODAL_DIV_ID + ' div {width:500px;margin:100px auto;background-color:#F1F2ED;border:1px solid #000;padding:20px;text-align:center;z-index:201;}');
GM_addStyle('.roboTable {width:100%;margin-bottom:20px;padding:3px;border-collapse:collapse;border: 1px solid #000;} tr.odd {background-color:white;font-weight:bold;} tr.even {background-color:beige;font-weight:bold;} thead tr {background-color:#ABAB9E;border-bottom:1px solid #000;} td {text-align:center;} tr.bench {background-color:#f1f2ed;font-weight:normal;} tr.total {background-color:yellow;font-weight:bold}');
addCloseAndRefresh(date);
}
/**
Add a close link and refresh to the modal
*/
function addCloseAndRefresh(date) {
var div = document.getElementById(MODAL_DIV_ID).childNodes[0];
var close = document.createElement("a");
close.id ="roboClose";
close.href = "#";
close.innerHTML = "[close]";
div.appendChild(close);
close.addEventListener('click',
function(e) { removeOverlay(); },
false);
var refresh = document.createElement("a");
refresh.id = "roboRefresh";
refresh.href = "#";
/* there is no need to display refresh button when in league
* wide stats mode so instead display the date for which the
* stats are reported
*/
if (date) {
refresh.innerHTML = date;
}
else {
refresh.innerHTML = "[refresh]";
refresh.addEventListener('click',
function(e) { removeOverlay(); getStats();},
false);
}
div.appendChild(refresh);
GM_addStyle('#roboRefresh {padding-left:10px;}');
}
/**
Modal window code
*/
function getViewportHeight() {
if (window.innerHeight!=window.undefined) return window.innerHeight;
if (document.compatMode=='CSS1Compat') return document.documentElement.clientHeight;
if (document.body) return document.body.clientHeight;
return window.undefined;
}
/**
Modal window code
*/
function getViewportWidth() {
if (window.innerWidth!=window.undefined) return window.innerWidth;
if (document.compatMode=='CSS1Compat') return document.documentElement.clientWidth;
if (document.body) return document.body.clientWidth;
return window.undefined;
}
/**
Modal window code
*/
function centerPopWin() {
var popMask = document.getElementById(MODAL_DIV_ID);
var width = popMask.offsetWidth;
var height = popMask.offsetHeight;
var fullHeight = getViewportHeight();
var fullWidth = getViewportWidth();
var scLeft,scTop;
if (self.pageYOffset) {
scLeft = self.pageXOffset;
scTop = self.pageYOffset;
} else if (document.documentElement && document.documentElement.scrollTop) {
scLeft = document.documentElement.scrollLeft;
scTop = document.documentElement.scrollTop;
} else if (document.body) {
scLeft = document.body.scrollLeft;
scTop = document.body.scrollTop;
}
popMask.style.height = fullHeight + "px";
popMask.style.width = fullWidth + "px";
popMask.style.top = scTop + "px";
popMask.style.left = scLeft + "px";
//check that user's screen is big enough for auto centering...
if (fullHeight > height) {
popMask.style.top = (scTop + ((fullHeight - height) / 2)) + "px";
}
if (fullWidth > width) {
popMask.style.left = (scLeft + ((fullWidth - width) / 2)) + "px";
}
}
/**
Attach functions to events
*/
function addEvent(obj, evType, fn) {
if (obj.addEventListener) {
obj.addEventListener(evType, fn, false);
return true;
} else if (obj.attachEvent) {
var r = obj.attachEvent("on" + evType, fn);
return r;
} else {
return false;
}
}
/**
Attach getStats function to date range menu items
*/
function addDateToMenuItem(menuItem, n) {
menuItem.addEventListener('click', function(e) {hideDateRange(); getStats(new Date(), n);}, false);
}
/**
Show date range for league summary 0-6 days ago
*/
function showDateRange() {
var id = STAT_BUTTON_ID;
var rangeId = id + 'daterange';
if (document.getElementById(rangeId)) {
hideDateRange(); // doesn't work, why?
}
/* replace button with pull down menu to show date range */
dateRange = document.createElement("div");
dateRange.id = rangeId;
dateRange.className = 'menulist';
GM_addStyle('#' + dateRange.id + '{position:absolute;top:207px;right:100px;z-index:200;background-color:#0781c8;color:#fff;text-align:left;}');
for (n = 0; n < 7; n++) {
var menuItem = document.createElement("a");
if (n == 0) {
menuItem.innerHTML = 'today';
}
else if (n == 1) {
menuItem.innerHTML = 'yesterday';
}
else {
menuItem.innerHTML = n + ' days ago';
}
addDateToMenuItem(menuItem, n);
var br = document.createElement("br");
dateRange.appendChild(menuItem);
dateRange.appendChild(br);
}
document.body.appendChild(dateRange);
}
/**
Hide date range for league summary
*/
function hideDateRange() {
var id = STAT_BUTTON_ID;
var rangeId = id + 'daterange';
var dateRange = document.getElementById(rangeId);
if (dateRange) {
dateRange.style.display = 'none';
}
}
/**
Add the blue show stats button
*/
function addShowStatsButton() {
var id = STAT_BUTTON_ID;
if (document.getElementById(id)) {
return;
}
var nodes = xpath(document, "//a[contains(@href,'stattracker')]");
var promoText = BUTTON_LABEL + (SCRIPT_MODE == LEAGUE ? ' (e)' : '');
if (nodes.snapshotItem(0)) {
var a = nodes.snapshotItem(0);
a.href = '#';
a.target = null;
a.innerHTML = promoText;
a.id = id;
if (SCRIPT_MODE == TEAM) {
a.addEventListener('click', function(e) {getStats(); return false;},false);
}
else {
/* in league mode, show a date range that allows user
* to pick the date they want to see the stats for
*/
a.addEventListener('click', function(e) {showDateRange(); return false;},false);
}
}
else {
var button = document.createElement("button");
document.body.appendChild(button);
button.id = id;
button.innerHTML = promoText;
if (SCRIPT_MODE == TEAM) {
button.addEventListener('click', function(e) {getStats();}, false);
}
else {
/* in league mode, show a date range that allows user
* to pick the date they want to see the stats for
*/
button.addEventListener('click', function(e) {showDateRange(); return false;},false);
}
GM_addStyle('#' + id + '{position:fixed;top:80px;right:80px;z-index:200;background-color:#0781C8;color:#fff;}');
}
}
/**
Remove modal window overlay
*/
function removeOverlay() {
if (document.getElementById(MODAL_DIV_ID)) {
document.body.removeChild(document.getElementById(MODAL_DIV_ID));
}
}
/**********************************************************************************************/
/**********************************************************************************************/
/**
TODO: issue 1
Set up the team stat table headers
*/
function setUpTable(tableId, pitcherOrBatter) {
var div = document.getElementById(MODAL_DIV_ID).childNodes[0];
var table = document.createElement("table");
table.className = "roboTable";
/* add space between buttons and table rows */
table.innerHTML += '';
if (pitcherOrBatter == BATTER) {
table.innerHTML +=
' ' +
'Name Status H/AB R HR RBI SB AVG OPS