// ==UserScript==
// @name Yahoo Football Matchups
// @namespace http://glenncarr.com/greasemonkey/yahoofantasy
// @include *football.fantasysports.yahoo.com/*
// @description Display opposing defensive team passing or rushing rankings for Yahoo fantasy football leagues
// @author Glenn Carr (glenn at glenncarr dot com)
// $LastChangedRevision$
// $LastChangedDate$
// ==/UserScript==
/*
about:config settings:
good_rgb_color - default: #33ff33 (green)
bad_rgb_color - default: #ff3333 (red)
font_rgb_color - default: #000000 (black)
Updates:
5-Dec-2007 - Added legend for colors
5-Dec-2007 - Added message while fetching stats
7-Dec-2007 - Moved color legend to bottom of page
30-Sep-2008 - Updated to work with Yahoo 2008 changes
12-Sep-2009 - Updated to display last year's stats for first week of the season
24-Sep-2009 - Fixed accidental swap of New England and New Orleans abbreviations
*/
(function() {
// Show last week's stats if we're in the first week of the season. Change (1) to (1|2) if you want to show last year's stats for weeks 1 and 2, change it to (1|2|3) to show last year's stats for weeks 1-3, etc.
var EARLY_WEEK = /week (1|2)\b/i;
var PASSING_DEFENSE_URL = 'http://sports.yahoo.com/nfl/stats/byteam?group=Defense&cat=Passing';
var RUSHING_DEFENSE_URL = 'http://sports.yahoo.com/nfl/stats/byteam?group=Defense&cat=Rushing';
String.prototype.stripTags = function() {
return this.replace(/<\/?[^>]+>|&[^;]+;|^\s+|\s+$/gi,'');
}
// Find the player tables
var playerTables = document.evaluate("//table[contains(@id,'statTable')]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
if ( playerTables.snapshotLength == 0 )
return;
// Find week and display last year's stats if it's early in the season
var week = document.evaluate("//div[@id='weeknav']/*", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
if ( week.snapshotLength == 0 )
week = document.evaluate("//div[@id='matchup-h1']/*", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var lastYear = null;
if ( week.snapshotLength > 0 )
{
week = week.snapshotItem( 0 );
if ( EARLY_WEEK.test( week.innerHTML ) )
{
lastYear = 1900 + new Date().getYear() - 1;
PASSING_DEFENSE_URL += '&year=season_' + lastYear;
RUSHING_DEFENSE_URL += '&year=season_' + lastYear;
}
}
var tables = new Array();
for ( var i = 0; i < playerTables.snapshotLength; i++ )
{
var table = playerTables.snapshotItem( i );
tables.push( table );
}
playerTables = tables;
var WORKING_IMG_URL = "data:image/gif,GIF89a%0A%00%0A%00%91%03%00%CC%CC%CC%FFff%FF%00%00%FF%FF%FF!%FF%" +
"0BNETSCAPE2.0%03%01%00%00%00!%F9%04%05%00%00%03%00%2C%00%00%00%00%0A%00%0A%00%00%02%17%9C'r%06%80%1A%" +
"02s'%AE%3Bqk%9A%E2%C3%81%14Gz%D9Q%00%00!%F9%04%05%00%00%03%00%2C%01%00%00%00%08%00%03%00%00%02%0A%9C%" +
"136%22%83%03%00S%10%14%00!%F9%04%05%00%00%03%00%2C%00%00%00%00%06%00%06%00%00%02%0C%9C%070%11%A8%7C%A" +
"2%11%22%D2X%00%00!%F9%04%05%00%00%03%00%2C%00%00%01%00%03%00%08%00%00%02%0A%1C%608%13%C1%BE%96%10c%16" +
"%00!%F9%04%05%00%00%03%00%2C%00%00%04%00%06%00%06%00%00%02%0A%04%86c%C9%1C%E1%A0%10l%16%00!%F9%04%05%" +
"00%00%03%00%2C%01%00%07%00%08%00%03%00%00%02%0A%04%86%23b%13%A1Dz%A9%00%00!%F9%04%05%00%00%03%00%2C%0" +
"4%00%04%00%06%00%06%00%00%02%0C%9C'r%A8%BB%11%06%00%03Jz%0A%00!%F9%04%09%00%00%03%00%2C%07%00%01%00%0" +
"3%00%08%00%00%02%0A%94f%A3%1A1%BD%00%18r%14%00%3B";
GM_addStyle( '\
IMG.gncTeam { padding-left: 2px } \
DIV#gncMatchupLegend { text-align: left; font-size: 77%; padding-left: 10px; background: #fff } \
TABLE#gncMatchupLegend { background: white; } \
TABLE#gncMatchupLegend TD { width: 15px; height: 15px; font-style: italic; padding: 0px; } \
' );
var legend = document.createElement( 'div' );
legend.id = 'gncMatchupLegend';
legend.innerHTML = 'Opposing Team Defense Colors Legend
';
var legendTable = document.createElement( 'table' );
legendTable.id = 'gncMatchupLegend';
legendTable.setAttribute( "cellspacing", "2" );
legendTable.innerHTML = '
Retrieving team defensive stats...  |
';
var yspcontent = document.getElementById( tables[ 0 ].id );
legend.appendChild( legendTable );
yspcontent.parentNode.insertBefore( legend, yspcontent.nextSibling );
var teamAbbrevs = new Array( 'Ari','Atl','Bal','Buf','Car','Chi','Cin','Cle','Dal','Den','Det','GB','Hou','Ind','Jac','KC','Mia','Min','NE','NO','NYG','NYJ','Oak','Phi','Pit','SD','Sea','SF','StL','TB','Ten','Was' );
var teamUrlAbbrevs = { Ari:'ari',Atl:'atl',Bal:'bal',Buf:'buf',Car:'car',Chi:'chi',Cin:'cin',Cle:'cle',Dal:'dal',Den:'den',Det:'det',GB:'gnb',Hou:'hou',Ind:'ind',Jac:'jac',KC:'kan',Mia:'mia',Min:'min',NE:'nwe',NO:'nor',NYG:'nyg',NYJ:'nyj',Oak:'oak',Phi:'phi',Pit:'pit',SD:'sdg',Sea:'sea',SF:'sfo',StL:'stl',TB:'tam',Ten:'ten',Was:'was' };
var teamCells = new Array();
var GOOD_COLOR = GM_getValue("good_rgb_color", "#33ff33");
GM_setValue("good_rgb_color", GOOD_COLOR);
var BAD_COLOR = GM_getValue("bad_rgb_color", "#ff3333");
GM_setValue("bad_rgb_color", BAD_COLOR);
var FONT_COLOR = GM_getValue("font_rgb_color", "#000000");
GM_setValue("font_rgb_color", FONT_COLOR);
fetchMatchupData();
function fetchMatchupData()
{
GM_xmlhttpRequest({
method: 'GET',
url: PASSING_DEFENSE_URL,
onload: getPassingDHandler( handlePassD ),
});
}
function getPassingDHandler( responseHandler )
{
return function (responseDetails)
{
if ( responseDetails.status == 200 )
responseHandler( responseDetails.responseText );
}
}
function handlePassD( responseText )
{
GM_xmlhttpRequest({
method: 'GET',
url: RUSHING_DEFENSE_URL,
onload: getRushingDHandler( displayMatchups, responseText ),
});
}
function getRushingDHandler( responseHandler, passingDResponseText )
{
return function (responseDetails)
{
if ( responseDetails.status == 200 )
responseHandler( responseDetails.responseText, passingDResponseText );
}
}
function displayMatchups( rushingDResponseText, passingDResponseText )
{
// Find all the team abbreviations
var reTeamAbbr = new RegExp( '^@?(' + teamAbbrevs.join( '|' ) + ')$' );
for ( var iTable = 0; iTable < playerTables.length; iTable++ )
{
var playerTable = playerTables[ iTable ];
for ( var iRow = 0; iRow < playerTable.rows.length; iRow++ )
{
var row = playerTable.rows[ iRow ];
if ( /^td$/i.test( row.cells[ 0 ].tagName ) )
{
for ( var iCell = 0; iCell < row.cells.length; iCell++ )
{
var cell = row.cells[ iCell ];
var cellText = cell.innerHTML.stripTags();
var matches = cellText.match( reTeamAbbr );
if ( matches )
{
cell.setAttribute( "gncTeam", teamUrlAbbrevs[ matches[ 1 ] ] );
teamCells.push( cell );
}
if ( /^player/i.test( cell.getAttribute( "class" ) ) )
{
var span = cell.getElementsByTagName( 'span' );
if ( span.length > 0 )
{
span = span[ 0 ];
var playerPos = span.innerHTML.stripTags().replace( /\(\S{2,3}\s+-\s+(\S+)\)/i, '$1' );
cell.style.paddingRight = '2px';
cell.parentNode.setAttribute( "gncPlayerPos", playerPos );
}
}
}
}
}
}
var rushingStats = parseStats( rushingDResponseText );
var passingStats = parseStats( passingDResponseText );
var colors = ColorTransition( BAD_COLOR, GOOD_COLOR, rushingStats.teams.length );
// Legend
legendTable.innerHTML = '| Bad matchups | Good matchups | ' + (lastYear != null ? '(Displaying matchups from last year)' : '' ) + ' |
';
var cols = Math.round( colors.length / 2 );
var tr = legendTable.rows[ 0 ];
tr.cells[ 0 ].setAttribute( "colspan", cols );
tr.cells[ 1 ].setAttribute( "colspan", colors.length - cols );
tr = document.createElement( 'tr' );
tr.style.height = '5px';
legendTable.appendChild( tr );
for ( var i = 0; i < colors.length; i++ )
{
var td = document.createElement( 'td' );
td.style.backgroundColor = colors[ i ];
tr.appendChild( td );
}
for ( var iCell = 0; iCell < teamCells.length; iCell++ )
{
var cell = teamCells[ iCell ];
var teamAbbr = cell.getAttribute( "gncTeam" );
var playerPos = cell.parentNode.getAttribute( "gncPlayerPos" ).toLowerCase();
var tip = '';
switch( playerPos )
{
case 'qb':
case 'wr':
case 'te':
case 'rb,te':
tip = "Pass " + buildToolTip( teamAbbr, passingStats );
cell.style.backgroundColor = colors[ getRank( teamAbbr, passingStats ) - 1 ];
break;
case 'rb':
tip = "Rush " + buildToolTip( teamAbbr, rushingStats );
cell.style.backgroundColor = colors[ getRank( teamAbbr, rushingStats ) - 1 ];
break;
}
teamCells[ iCell ].setAttribute( "title", tip );
}
}
function parseStats( responseText )
{
var table = document.getElementById( 'gncStatTable' );
if ( table == null )
{
table = document.createElement( 'table' );
table.style.display = 'none';
table.id = 'gncStatTable';
document.body.appendChild( table );
}
var tables = responseText.replace( /\r\n+/g, '' ).split( /]+>/i );
for ( var iTable = 0; iTable < tables.length; iTable++ )
{
if ( /class="ysptblthbody1"/i.test( tables[ iTable ] ) )
{
table.innerHTML = tables[ iTable ].replace( /<\/table>/i, '' );
return extractTableStats( table );
}
}
}
function extractTableStats( table )
{
var statNames = new Array();
var teams = new Array();
var stats = {};
for ( var iRow = 0; iRow < table.rows.length; iRow++ )
{
var row = table.rows[ iRow ];
// header
if ( iRow == 0 )
{
statNames.push( 'Rank' );
for ( var iCell = 1; iCell < row.cells.length; iCell++ )
{
var cell = row.cells[ iCell ];
var cellText = cell.innerHTML.stripTags();
if ( cellText.length > 0 )
statNames.push( cellText );
}
}
// data
else
{
var teamStats = new Array();
var teamAbbr = '';
for ( var iCell = 0; iCell < row.cells.length; iCell++ )
{
var cell = row.cells[ iCell ];
var cellText = cell.innerHTML.stripTags();
// team
if ( iCell == 0 )
{
teamAbbr = cell.getElementsByTagName( 'a' )[ 0 ].href.replace( /^.*\/([a-z]+$)/i, '$1' );
teamStats.push( iRow ); // rank
teams.push( teamAbbr );
}
else
{
if ( cellText.length > 0 )
teamStats.push( cellText );
}
}
stats[ teamAbbr ] = teamStats;
}
}
return { teams:teams, statNames:statNames, stats:stats };
}
function buildToolTip( teamAbbr, teamStats )
{
if ( !teamStats.stats.hasOwnProperty( teamAbbr ) )
return '';
var tip = new Array();
var stats = teamStats.stats[ teamAbbr ];
var statNames = teamStats.statNames;
for ( var i = 0; i < stats.length; i++ )
{
switch( statNames[ i ].toLowerCase() )
{
case 'rank':
case 'avg':
case 'rushyds/g':
case 'passyds/g':
case 'td':
case 'int':
case 'sack':
tip.push( statNames[ i ].replace( /pass|rush/i, '' ) + ': ' + stats[ i ] );
break;
default:
break;
}
}
return tip.join( ', ' );
}
function getRank( teamAbbr, teamStats )
{
if ( !teamStats.stats.hasOwnProperty( teamAbbr ) )
return -1;
var stats = teamStats.stats[ teamAbbr ];
var statNames = teamStats.statNames;
for ( var i = 0; i < stats.length; i++ )
{
switch( statNames[ i ].toLowerCase() )
{
case 'rank':
return parseInt( stats[ i ], 10 );
}
}
}
function ColorTransition(start, end, steps)
{
var patterns = {};
patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
var parseColor = function(s)
{
if (s.length == 3) { return s; }
var c = patterns.hex.exec(s);
if (c && c.length == 4)
{
return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
}
c = patterns.rgb.exec(s);
if (c && c.length == 4)
{
return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
}
c = patterns.hex3.exec(s);
if (c && c.length == 4)
{
return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
}
return null;
};
var outputColors = [];
var startColor = currentColor = parseColor(start);
var endColor = parseColor(end);
var deltas = [];
for (var rgbIndex = 0; rgbIndex < currentColor.length; rgbIndex++)
{
deltas[rgbIndex] = Math.abs(currentColor[rgbIndex] - endColor[rgbIndex]) / steps;
}
for (var step = 0; step < steps; step++)
{
if (step == steps -1)
{
currentColor = endColor;
}
outputColors[step] = 'rgb('+Math.floor(currentColor[0])+','+Math.floor(currentColor[1])+','+Math.floor(currentColor[2])+')';
for (var rgbIndex = 0; rgbIndex < currentColor.length; rgbIndex++)
{
if ( startColor[rgbIndex] < endColor[rgbIndex] )
currentColor[rgbIndex] += deltas[rgbIndex];
else
currentColor[rgbIndex] -= deltas[rgbIndex];
}
}
return outputColors;
}
})();