NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// iRacing Online Friends // Copyright (c) 2013, Rob Kodey // var RK_DEBUG = 1; var RK_FRIENDS = 1; // Set to 0 to turn off online friends var RK_SERIES_FILTER = 0; // Set to 0 to turn off the series drop-down filter var RK_SET_SELECTS = 0; // Set to 0 to turn off the other automatic select-box selections // // ==UserScript== // @name iRacing Online Friends // @version 1.15 // @copyright 2013, Rob Kodey // @licence MIT // @namespace http://www.kodey.com/ // @description Highlight your Friends and Watched Drivers on the Dashboard and Series Session pages, so you know where they are driving. // @include https://members.iracing.com/membersite/member/* // @grant GM_xmlhttpRequest // ==/UserScript== // // Changes: // TODO // Favorite series instead of filter? http://members.iracing.com/jforum/posts/list/0/1973793.page // http://members.iracing.com/jforum/posts/list/0/1975064.page // Show time to upcoming session // http://members.iracing.com/membersite/member/GetDriverStatus?friends=1&studied=1 var RK_Version = 1.15; // v1.15 04/27/2013 // Updated to support the new iRacing Build // v1.14 04/08/2013 // Increased the delay between calls, based on some code warnings coming back from iRacing (sorry!) // v1.13 09/10/2012 // Re-wrote, and hopefully fixed, the Hosted Sessions support, as iRacing organizes the info very differently on that page // v1.12 06/09/2012 // Wow - it's been almost a year since the last update, with 2300 installs!! Thanks! // Fixed: Hosted sessions work again, and show where your friends and studied drivers are registered // Re-Added: Mixed-Class stats page car auto-selection - needed for Firefox // Fixed: Major Chrome issue by changing the core system that pulls javascript variables out of the page // v1.11 06/20/2011 // Added: Support for Spectator Sessions screen // Added: Driver helmets // Added: The series filter is back, now with an all new selection dialog to let you choose what you want to see // v1.10 12/23/2010 // Fixed: Detection of the Dashboard page, since iRacing's URL structure changes slightly // Temporarily removed: The Series filter, until iRacing brings back the Ticker settings // v1.9 11/07/2010 // Fixed: The "Planner" & "Standings" dashboard widgets automatically select your active Race-Panel series // v1.8 11/02/2010 // Fixed: "Hide yourself" // Updated: The Update check dialog, and added option to turn it off. (Delete the cookie to turn back on) // Added: Series filter for Race Panel, Series Stats, and Race Planner Widget so they match your ticker series preferences // v1.7 10/30/2010 // Updated: Support for Season-4 web updates from iRacing // Added: Friend highlighting for Races & Qualifiers to Series Sessions Page and Race Widget // Added: "Personal Best" stats will automatically select your active Race-Panel car // Added: Update check for new versions of the script // v1.6 06/02/2010 // This release has nothing to do with friends - perhaps I should rename the script? // (Retired) Added: The "Sereis Stats" page will automatically select your active Race-Panel car // Added: Filter the Race Panel's "Series Selection" drop-down so that it matches your ticker series preferences // v1.5 05/05/2010 // Added: support for the new iRacing site design // Added: support for the Join a Hosted session page // Added: (optional) support for past events pages: Hosted (Results), Events (Results, Replays), // Stats (Personal, Friends, Studied) // Added: options to turn on/off highlighting for any individual page // Fixed: minor bug in the filter that skipped querying empty sessions // Fixed: friend/watched matching of members with customer IDs < 10000 (aka shorter than 5 digits!) // v1.1 04/26/2010 // Fixed: encoding issue for driver names with extended characters // v1.0 04/18/2010 // Chrome and Opera support! // Driver names now link to Career Stats // New display formatting looks much better! (hopefully!!) // Where possible, the callback to retrieve the driver list is skipped, to be nice to the servers // Friends are now re-highlighted when iRacing refreshes panels, after a couple seconds delay // v0.3 04/13/2010 // Detection of "slow widgets" on the Dashboard should be 100% reliable now // Getting closer to supporting Chrome, and Opera... // v0.2 04/11/2010 // Fixed Dashboard detection vs. Press Room // session info requests are now spread out a bit, to be nice to the servers // // var RK_oGlobals; var RK_sPage; var RK_MaxLoops = 50; var RK_LoopWait = 500; var RK_DriverWait = 200; var RK_Update = 86400000; // Check once per day var RK_Script = 74072; var RK_sImages = ".//IMG[@name]"; var RK_sLinks = ".//A[@href]"; var RK_oRows = new Object(); var RK_oIDs = new Object(); var RK_oDriverTR = new Object(); var RK_oDriverTD = new Object(); var RK_sStyleTD = 'padding:2px; border-bottom:2px solid #000000;'; var RK_Cookie = 'OnlineFriendsPrefs'; var RK_SELECT = 'PARENT_SELECT'; var RK_FILTER = 'SeriesFilter'; var RK_FILTER_LIST = 'SeriesFilterList'; var RK_FILTERSELECT = 'RK_FILTER_SELECT'; var RK_ImgPop = '<img src="http://www.kodey.com/iRacing/new_window.gif">'; var RK_Z = 1000; var RK_LicIcons = { 1 : '/member_images/widgets/licenses/stats_licence_r.png', 2 : '/member_images/widgets/licenses/stats_licence_d.png', 3 : '/member_images/widgets/licenses/stats_licence_c.png', 4 : '/member_images/widgets/licenses/stats_licence_b.png', 5 : '/member_images/widgets/licenses/stats_licence_a.png', 6 : '/member_images/widgets/licenses/stats_licence_p.png', 7 : '/member_images/widgets/licenses/stats_licence_pwc.png' } var RK_oSessionCellLookup = { 3:1, 4:3, 5:2 }; // var oRK_SessionDivOffset = { 1:2, 2:2, 3:2 }; // div offset var RK_oPrefs = { Self : true, Dashboard : true, Sessions : true, Join : true, Hosted : true, Results : true, Replays : true, Stats : true, Spectator : true, SeriesResults : true, SeriesFilter : false, SkipUpdateCheck : false, LastUpdate : 0 }; var RK_oURLs = { '/membersite/member/home.do' : 'Home', '/membersite/member/seriessessions.do' : 'Sessions', '/membersite/member/hostedsessions.do' : 'Join', '/membersite/member/hostedresults.jsp' : 'Hosted', '/membersite/member/results.jsp' : 'Results', '/membersite/member/replays.jsp' : 'Replays', '/membersite/member/careerstats.do' : 'Stats', '/membersite/member/spectator.jsp' : 'Spectator', '/membersite/member/seriesstandings.do' : 'Series', '/membersite/member/seriesraceresults.do': 'SeriesResults' }; var RK_sCustDisplayURL = 'http://members.iracing.com/membersite/member/GetCustDisplayInfo'; var RK_sDriverStatusURL = 'http://members.iracing.com/membersite/member/GetDriverStatus'; var RK_sOpenSessionURL = 'http://members.iracing.com/membersite/member/GetOpenSessionDrivers'; var RK_sPrivateSessionURL = 'http://members.iracing.com/membersite/member/GetPrivateSessionRegistered'; var RK_sSessionDriversURL = 'http://members.iracing.com/membersite/member/GetSessionDrivers'; var RK_sSessionTimesURL = 'http://members.iracing.com/membersite/member/GetSessionTimes'; var TM_sSeriesResultsURL = 'http://members.iracing.com/membersite/member/SeriesRaceResults'; ////////////////////////////////////////////////// function RK_log(msg) { if(console && RK_DEBUG) { console.log(msg); } } ////////////////////////////////////////////////// function RK_SetCookie(name, value, nDays) { var dt = new Date(); dt.setDate(dt.getDate()+nDays); document.cookie = name+ "=" +escape(value) + ((nDays==null) ? "" : "; expires="+dt.toUTCString()); // + "; path=/membersite" } // RK_SetCookie ////////////////////////////////////////////////// function RK_ReadCookies() { var oCook = new Object(); var aCookies = document.cookie.split('; '); for(var i=0; i < aCookies.length; i++) { var aNVP = aCookies[i].split("="); oCook[aNVP[0]]= aNVP[1]; } return(oCook); } // RK_ReadCookies ////////////////////////////////////////////////// function RK_SetPrefs() { RK_log("RK_SetPrefs: " + RK_oPrefs.LastUpdate); RK_SetCookie(RK_Cookie, JSON.stringify(RK_oPrefs), 100); } // RK_SetPrefs ////////////////////////////////////////////////// var RK_oCookies = RK_ReadCookies(); if(RK_oCookies[RK_Cookie]) RK_oPrefs = JSON.parse(unescape(RK_oCookies[RK_Cookie])); RK_SetPrefs(); ////////////////////////////////////////////////// function RK_xpath(query, context) { if(!context) context = document; return document.evaluate(query, context, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); } ////////////////////////////////////////////////// function RK_GetDriverName(oDriver) { var name = decodeURIComponent(oDriver.displayname || oDriver.dn || oDriver.name); name = name.replace(/\+/g,' '); RK_log("RK_GetDriverName: " + name); RK_log("RK_GetDriverName driver: " + JSON.stringify(oDriver)); var oHelmet = oDriver.helmet || oDriver; var sClass = RK_oIDs[oDriver.custid] || ''; var sColors = (oHelmet.c1 || oHelmet.helmcolor1) + ',' + (oHelmet.c2 || oHelmet.helmcolor2) + ',' + (oHelmet.c3 || oHelmet.helmcolor3); var sPattern = oHelmet.p || oHelmet.helmpattern; var sLicense = oHelmet.ll || oHelmet.maxlicenselevel; var src = RK_oGlobals.simStatus ? ( 'http://127.0.0.1:32034/helmet.png?size=5&pat='+sPattern+'&lic='+sLicense+'&colors='+sColors) : '/membersite/images/default/helmet/size_5/helmet.png'; return( '<div style="padding:0px; text-align:left; height:22px; overflow:hidden;" class="'+sClass+ '"> <img style="vertical-align: middle; padding:1px;" src="'+src+ '"> <a class="stats_table_link" href="CareerStats.do?custid='+oDriver.custid+'">'+name+'</a></div>'); } // RK_GetDriverName ////////////////////////////////////////////////// function RK_InsertDriver(oDriver, cell, oConfig) { // RK_log("RK_InsertDriver"); if(!RK_oDriverTR[oConfig.name]) { var newTR = document.createElement('tr'); while(cell.tagName != 'TD' && cell.parentNode) cell = cell.parentNode; cell.parentNode.parentNode.insertBefore(newTR, cell.parentNode.nextSibling); newTR.innerHTML = '<td style="'+RK_sStyleTD+'" colspan="'+oConfig.nSpanL+'"></td><td style="'+RK_sStyleTD+'" colspan="'+oConfig.nSpanR+'"></td>'; RK_oDriverTD[oConfig.name] = RK_xpath('.//TD[last()]', newTR).snapshotItem(0); RK_oDriverTR[oConfig.name] = newTR; } var sPos = oDriver.pos ? oDriver.pos+'.' : ''; RK_oDriverTD[oConfig.name].previousSibling.innerHTML += '<div style="padding:4px 0px 0px 0px; text-align:right; height:18px;">'+sPos+'</div>'; RK_oDriverTD[oConfig.name].innerHTML += RK_GetDriverName(oDriver); } // RK_InsertDriver ////////////////////////////////////////////////// function RK_CheckMatch(oDriver, session, oConfig) { if(RK_oIDs[oDriver.custid]) { var tr = RK_oRows[session]; var cell = RK_xpath(RK_sImages, tr).snapshotItem(0) || RK_xpath(RK_sLinks, tr).snapshotItem(0); RK_InsertDriver(oDriver, cell, oConfig); } } // RK_CheckMatch ////////////////////////////////////////////////// function RK_GetDriverInfo(url, delay, oConfig) { window.setTimeout(function() { RK_log("RK_GetDriverInfo: " + url); GM_xmlhttpRequest( { method: 'GET', url: url, onload: function(res) { // RK_log("RK_GetDriverInfo: " + res.responseText); var oDrivers = JSON.parse(res.responseText); // console.log(JSON.stringify(oDrivers)); var session; if(oDrivers.rows) { session = oDrivers.subsessionid; oDrivers = oDrivers.rows; } else { session = oDrivers[0].subsessionid; } RK_oDriverTR[oConfig.name] = null; RK_oDriverTD[oConfig.name] = null; for(var i=0; i < oDrivers.length; i++) { oDrivers[i].pos = i+1; RK_CheckMatch(oDrivers[i], session, oConfig); } } }); }, delay); } // RK_GetDriverInfo ////////////////////////////////////////////////// function RK_AddClickPref(ele, sName, fnOverride) { ele.style.cursor = 'pointer'; var fnToggle = function() { RK_oPrefs[sName] = (RK_oPrefs[sName] ? false : true); RK_SetPrefs(); document.location.reload(); }; if(fnOverride) fnToggle = fnOverride; ele.addEventListener('click', fnToggle, false); } // RK_AddClickPref ////////////////////////////////////////////////// function RK_WriteFriendPref(sName, oParent, sClass) { var oDiv = document.createElement('div'); oDiv.className = sClass; oDiv.style.cssText = 'text-align:right; color:#646464; font-weight:bold; padding:2px;'; RK_AddClickPref(oDiv, sName); oParent.appendChild(oDiv); oDiv.innerHTML = '<span class="stats_table_text" style="padding:2px;">' + (RK_oPrefs[sName] ? 'Hide ' : 'Show ') + (sName == 'Self' ? 'yourself' : 'friends') + '</span>'; } // RK_WriteFriendPref ////////////////////////////////////////////////// function RK_ProcessDrivers(xRows, oConfig) { RK_log('RK_ProcessDrivers: ' + oConfig.name + ': ' +xRows.snapshotLength); xRows.snapshotItem(2).id = 'RK_'+oConfig.name; var xLastRow; for(var i = 0; i < xRows.snapshotLength; i++) { var oRow = xRows.snapshotItem(i); var sess = ''; // Look for helmet images var xImages = RK_xpath(RK_sImages, oRow); //RK_log('RK_ProcessDrivers: helmet images: ' + xImages.snapshotLength); for(var j = 0; (!sess && j < xImages.snapshotLength); j++) { //RK_log('RK_ProcessDrivers: helmet name: ' + xImages.snapshotItem(j).name); var aMatches = xImages.snapshotItem(j).name.match(/(\d+)/); if(aMatches) { sess = aMatches[1]; } } // Then, if not found, look for results links var xLinks = RK_xpath(RK_sLinks, oRow); for(var j = 0; (!sess && j < xLinks.snapshotLength); j++) { //RK_log('RK_ProcessDrivers: results link: ' + xLinks.snapshotItem(j).href); var aMatches = unescape(xLinks.snapshotItem(j).href).match(/launchEventResults?\((\d+),\s*\d+\)/i); if(aMatches) { sess = aMatches[1]; } } //RK_log('RK_ProcessDrivers: session: ' + sess); if(sess && RK_oPrefs[RK_sPage]) { RK_oRows[sess] = oRow; var reZero = oConfig.reZero || /[>(]\s*0\/\d+\s*[)<]/; if(!(oRow.innerHTML.match(reZero))) { var url = oConfig.url + '?requestindex='+(i+1)+'&subsessionid='+sess; RK_GetDriverInfo(url, i*RK_DriverWait, oConfig); } else if(RK_DEBUG) { oRow.childNodes[0].innerHTML += 'skipped'; } } if(oRow.childNodes.length > 1) { xLastRow = oRow; } } var tr = document.createElement('tr'); var tdL = document.createElement('td'); // tdL.style.cssText = RK_sStyleTD; tdL.colSpan = oConfig.nSpanL; tr.appendChild(tdL); var tdR = document.createElement('td'); tdR.style.cssText = RK_sStyleTD; tdR.colSpan = oConfig.nSpanR; tr.appendChild(tdR); xLastRow.parentNode.insertBefore(tr, xLastRow.nextSibling); if(RK_oPrefs[RK_sPage]) RK_WriteFriendPref('Self', tdR, ''); RK_WriteFriendPref(RK_sPage, tdR, 'stats_friend_tr'); // var oSelfDiv = document.createElement('div'); // oSelfDiv.style.cssText = 'text-align:right; color:#646464; font-weight:bold;'; // oSelfDiv.addEventListener('click', function() // { // RK_oPrefs.Self = !RK_oPrefs.Self // RK_SetPrefs(); // document.location.reload(); // }, false); // tdR.appendChild(oSelfDiv); // oSelfDiv.innerHTML = '<span class="stats_table_text" style="cursor:pointer;">'+(RK_oPrefs.Self ? 'Hide' : 'Show') + ' yourself</span>'; } // RK_ProcessDrivers ////////////////////////////////////////////////// function RK_ProcessHosted(xRows, oConfig) { RK_log('RK_ProcessHosted: ' + oConfig.name + ': ' +xRows.snapshotLength); xRows.snapshotItem(2).id = 'RK_'+oConfig.name; RK_log("RK_ProcessHosted: Getting hosted sessions"); GM_xmlhttpRequest( { method: 'GET', url: 'http://members.iracing.com/membersite/member/GetHostedSessions?ts=0', // headers: { "Content-Type": "application/x-www-form-urlencoded" }, onload: function(res) { RK_log("RK_ProcessHosted: done"); var tmp1 = res.responseText.replace(/\+/g," "); eval("var aHosted="+tmp1+";"); var oHosted = {}; for(var i = 0; i < aHosted.all.length; i++) { // cnovert the array into a hash oHosted[aHosted.all[i].privatesessionid] = aHosted.all[i]; } var xLastRow; for(var i = 0; i < xRows.snapshotLength; i++) { var oRow = xRows.snapshotItem(i); var hosted = null; // Look for helmet to get the session var xImages = RK_xpath(RK_sImages, oRow); for(var j = 0; (j < xImages.snapshotLength); j++) { RK_log('RK_ProcessHosted: helmet name: ' + xImages.snapshotItem(j).name); var aMatches = xImages.snapshotItem(j).name.match(/(\d+)/); if(aMatches && !hosted) { hosted = oHosted[aMatches[1]]; } } if(hosted) { var pvtid = hosted.privatesessionid; var sess = hosted.subsessionid; RK_log('RK_ProcessHosted: '+i+' session: '+sess+', name: '+hosted.sessionname); if(sess && RK_oPrefs[RK_sPage]) { RK_oRows[sess] = oRow; var reZero = oConfig.reZero || /[>(]\s*0\/\d+\s*[)<]/; if(!(oRow.innerHTML.match(reZero))) { var url = oConfig.url + '?requestindex='+(i+1)+'&pvtid='+pvtid+'&ssid='+sess; RK_GetDriverInfo(url, i*RK_DriverWait, oConfig); } else if(RK_DEBUG) { oRow.childNodes[0].innerHTML += 'skipped'; } } if(oRow.childNodes.length > 1) { xLastRow = oRow; } } } var tr = document.createElement('tr'); var tdL = document.createElement('td'); // tdL.style.cssText = RK_sStyleTD; tdL.colSpan = oConfig.nSpanL; tr.appendChild(tdL); var tdR = document.createElement('td'); tdR.style.cssText = RK_sStyleTD; tdR.colSpan = oConfig.nSpanR; tr.appendChild(tdR); xLastRow.parentNode.insertBefore(tr, xLastRow.nextSibling); if(RK_oPrefs[RK_sPage]) RK_WriteFriendPref('Self', tdR, ''); RK_WriteFriendPref(RK_sPage, tdR, 'stats_friend_tr'); } }); } // RK_ProcessHosted ////////////////////////////////////////////////// function RK_GetRegistered(func) { var url = RK_sDriverStatusURL; RK_log("RK_GetRegistered: " + url); GM_xmlhttpRequest( { method: 'POST', url: url, data: 'friends=1&studied=1&onlineOnly=1', headers: { "Content-Type": "application/x-www-form-urlencoded" }, onload: function(res) { RK_log("RK_GetRegistered: done"); var oDrivers = JSON.parse(res.responseText); var oDrvSess = new Object(); for(var i = 0; i < oDrivers.fsRacers.length; i++) { var oDriver = oDrivers.fsRacers[i]; if(oDriver.sessionId) { // oDriver.sessionId = '12681297'; RK_log('RK_GetRegistered: ' + oDriver.name + ", Session: " + oDriver.sessionId + ", Status: " + oDriver.subSessionStatus); if(!oDrvSess[oDriver.sessionId]) oDrvSess[oDriver.sessionId] = new Array(); oDrvSess[oDriver.sessionId].push(oDriver); // if(oDriver.subSessionStatus != 'subses_running') // { // alert('RK_GetRegistered: ' + oDriver.name + ", Session: " + oDriver.sessionId + ", Status: " + oDriver.subSessionStatus); // } } } func(oDrivers, oDrvSess); } }); } // RK_GetRegistered ////////////////////////////////////////////////// function RK_RaceRegistered(xRows, oConfig) { RK_log('RK_RaceRegistered: ' + oConfig.name + ': ' +xRows.snapshotLength); xRows.snapshotItem(2).id = 'RK_'+oConfig.name; RK_GetRegistered(function(oDrivers, oDrvSess) { var xLastRow; for(var i = 0; i < xRows.snapshotLength; i++) { var oRow = xRows.snapshotItem(i); var sess = ''; var cell; var xDivs = RK_xpath('.//DIV[@id]', oRow); for(var j = 0; (!sess && j < xDivs.snapshotLength); j++) { var aMatches = xDivs.snapshotItem(j).id.match(/^(\d{7,})$/); if(aMatches) { cell = xDivs.snapshotItem(j); sess = aMatches[1]; RK_log('RK_RaceRegistered: ' + sess); } } if(sess && RK_oPrefs[RK_sPage]) { RK_oDriverTR[oConfig.name] = null; RK_oDriverTD[oConfig.name] = null; var aDrivers = oDrvSess[sess] || new Array(); for(var j = 0; j < aDrivers.length; j++) { var oDriver = aDrivers[j]; RK_InsertDriver(oDriver, cell, oConfig); } } if(oRow.childNodes.length > 1) { xLastRow = oRow; } } var tr = document.createElement('tr'); var tdL = document.createElement('td'); tdL.colSpan = oConfig.nSpanL; tr.appendChild(tdL); var tdR = document.createElement('td'); tdR.style.cssText = RK_sStyleTD; tdR.colSpan = oConfig.nSpanR; tr.appendChild(tdR); xLastRow.parentNode.insertBefore(tr, xLastRow.nextSibling); if(RK_oPrefs[RK_sPage]) RK_WriteFriendPref('Self', tdR, ''); RK_WriteFriendPref(RK_sPage, tdR, 'stats_friend_tr'); }); } // RK_RaceRegistered ////////////////////////////////////////////////// function RK_WaitForElement(oConfig, fn, min, count) { if(!count) count = 1; if(!min) min = 2; RK_log('RK_WaitForElement: ' + count + ': ' + oConfig.name); var mutex = document.getElementById('RK_'+oConfig.name); if(!mutex) { var xRes = RK_xpath('//TABLE[@'+oConfig.type+'="'+oConfig.name+'"]//TR'); RK_log('RK_WaitForElement: ' + xRes.snapshotLength + ': ' + oConfig.name); if(xRes.snapshotLength > min) { fn(xRes, oConfig); } else if(count <= RK_MaxLoops) { window.setTimeout(function() { RK_WaitForElement(oConfig, fn, min, count+1); }, RK_LoopWait); } } } // RK_WaitForElement ////////////////////////////////////////////////// function RK_GetParentSelect(oOption) { if(oOption && oOption.tagName.toLowerCase() == 'option') { var oSelect = oOption; do { oSelect = oSelect.parentNode; } while(oSelect.tagName.toLowerCase() != 'select' && oSelect.parentNode); return(oSelect); } } // RK_GetParentSelect ////////////////////////////////////////////////// function RK_GetDropDown(xContainer) { RK_log('RK_GetDropDown'); var oOptions = new Object(); if(xContainer.snapshotLength) { var xGroups = RK_xpath('.//OPTGROUP', xContainer.snapshotItem(0)); for(var i=0; i< xGroups.snapshotLength; i++) { var oGroup = xGroups.snapshotItem(i); oGroup.style.color = '#808080'; oGroup.style.fontStyle = 'italic'; // oGroup.style.fontWeight = 'normal'; RK_log('RK_GetDropDown: Group: ' + oGroup.label + ':' + oGroup.style.fontWeight); } var xOptions = RK_xpath('.//OPTION', xContainer.snapshotItem(0)); for(var i=0; i< xOptions.snapshotLength; i++) { var oOption = xOptions.snapshotItem(i); if(oOption.disabled) { oOption.style.color = '#808080'; oOption.style.fontStyle = 'normal'; // oGroup.style.fontWeight = 'normal'; } else { oOption.style.color = '#000000'; oOption.style.fontStyle = 'normal'; // oGroup.style.fontWeight = 'bold'; } oOptions[oOption.value] = oOption; oOptions[RK_SELECT] = RK_GetParentSelect(oOption); // RK_log('RK_GetDropDown: Option: ' + oOption.value + ':' + oOption.style.fontWeight); } } return(oOptions); } // RK_GetDropDown ////////////////////////////////////////////////// function RK_RemoveOption(oOption) { if(oOption && oOption.parentNode) { // RK_log('RK_RemoveOption: Removing: ' + oOption.text); RK_GetParentSelect(oOption).remove(oOption.index); } } // RK_RemoveOption ////////////////////////////////////////////////// function RK_GetSeriesSelection(oSeries) { var html = ''; var td = '<td style="vertical-align:middle; padding:2px; white-space:nowrap;">'; var aFilters = RK_oPrefs[RK_FILTER_LIST] || (new Array()); if(oSeries) { html += td+'<input type="checkbox" name="'+RK_FILTERSELECT+'" value="'+oSeries.seriesid+'" style="margin:4px; vertical-align:middle;" '+(aFilters[oSeries.seriesid] ? '' : 'checked="true"')+'>'; html += '<img src="'+(RK_LicIcons[oSeries.serieslicgroupid]||'')+'" style="vertical-align:middle;"></td>'; html += td+'<div style="width:60px; height:22px; background:url(/'+unescape(oSeries.whatshotimg)+');"> </div></td>'; html += td+oSeries.seriesname.replace(/( race)? series/i,'')+/*' : '+oSeries.seriesid+' : '+oSeries.i+' : '+oSeries.licgroupid+' : '+oSeries.serieslicgroupid+*/'</td>'; } else html += '<td></td><td></td><td></td>'; return(html); } // RK_GetSeriesSelection ////////////////////////////////////////////////// function RK_ShowSeriesFilter() { RK_log('RK_ShowSeriesFilter'); var aSeries = RK_oGlobals.SeasonListing; if(aSeries) { var id = 'RK_SERIES_FILTER'; var id_toggle = id+'_TOGGLE'; var div = document.createElement('div'); div.id = id; div.className = 'stats_friend_tr'; div.style.cssText = 'position:absolute; left:100px; top:100px; border:2px solid #000000; z-index:'+(RK_Z++)+'; padding:3px; text-align:left;'; var html = ''; html += '<div style="text-align:center;">The following Series are currently displayed. <b>Uncheck</b> a series to hide it from the Series List.</div>'; html += '<div style="text-align:center;">Note: If iRacing adds new series, they will not be hidden by default.</div>'; var oSeriesTable = new Object(); for(var i=0; i<aSeries.length; i++) { var oSeries = aSeries[i]; oSeries.i = i; if(oSeries.active) { if(!(oSeriesTable[oSeries.category])) oSeriesTable[oSeries.category] = new Array(); oSeriesTable[oSeries.category].push(oSeries); } } function sortFunc(a,b) { var ret; ret = a.serieslicgroupid - b.serieslicgroupid; if(!ret) ret = a.licgroupid - b.licgroupid; if(!ret) ret = a.seriesname.toLowerCase() > b.seriesname.toLowerCase(); return(ret); } oSeriesTable[1].sort(sortFunc); oSeriesTable[2].sort(sortFunc); var max = oSeriesTable[1].length > oSeriesTable[2].length ? oSeriesTable[1].length : oSeriesTable[2].length; // html += '<div style="overflow:auto; height:300px; border:1px solid black;"><table border="0" cellspacing="0" cellpadding="0" style="margin:10px;">'; html += '<div><table border="0" cellspacing="0" cellpadding="0" style="margin:10px;">'; for(var i=0; i<max; i++) { html += '<tr>'; html += '<td style="width:10px;"></td>'; html += RK_GetSeriesSelection(oSeriesTable[1][i]); html += '<td style="width:20px;"></td>'; html += RK_GetSeriesSelection(oSeriesTable[2][i]); html += '<td style="width:10px;"></td>'; html += '</tr>'; } html += '</table></div>'; // html += '<div>Please visit the <a target="_blank" href="http://userscripts.org/scripts/show/'+RK_Script+'">UserScript page '+RK_ImgPop+'</a> to upgrade.</div>'; // html += '<div id="'+whatsnewid+'"></div>'; // html += '<br><div>Or, visit the <a target="_blank" href="http://members.iracing.com/jforum/posts/list/1275006.page">iRacing Forum thread '+RK_ImgPop+'</a> for more info.</div>'; html += '<div style="text-align:center;"><input type="checkbox" id="RK_FILTER_TOGGLE" style="margin:10px 4px; vertical-align:middle;" '+(RK_oPrefs[RK_FILTER] ? 'checked="true"' : '')+'>Turn on the filter (Uncheck this to show all series)</div>'; html += '<div style="text-align:center;"><a id="'+id_toggle+'" onclick="return(false);" href="" style="margin-right:10px;">Save</a>|'; html += '<a href="" onclick="javascript:document.getElementById(\''+id+'\').style.display=\'none\'; return(false);" style="margin-left:10px;">Cancel</a></div><br>'; div.innerHTML = html; var child = document.body.firstChild; if(child) { child.parentNode.insertBefore(div, child); } RK_AddClickPref(document.getElementById(id_toggle), RK_FILTER, function() { var aChecks = document.getElementsByName(RK_FILTERSELECT); var oFilter = {}; for(var i=0; i<aChecks.length; i++) { if(!(aChecks[i].checked)) oFilter[aChecks[i].value] = 1; } RK_oPrefs[RK_FILTER_LIST] = oFilter; RK_oPrefs[RK_FILTER] = document.getElementById('RK_FILTER_TOGGLE').checked ? true : false; RK_SetPrefs(); document.location.reload(); }); } } // RK_ShowSeriesFilter ////////////////////////////////////////////////// function RK_Addfilter(oObj) { if(oObj) { var oSelect = oObj[RK_SELECT]; if(oSelect) { var oDiv = document.createElement('div'); oDiv.style.position = oSelect.style.position; oDiv.style.left = oSelect.style.left; oDiv.style.top = oSelect.style.top; // oDiv.style.width = (parseInt(oSelect.style.width) + 16) + 'px'; oSelect.style.position = ''; oSelect.style.left = ''; oSelect.style.top = ''; oSelect.style.width = (parseInt(oSelect.style.width) - 22) + 'px'; var oFilter = document.createElement('span'); // oFilter.className = ''; oFilter.innerHTML = ' <a href="" onclick="return(false);" class="racingpanel_link" style="font-weight:'+(RK_oPrefs[RK_FILTER]&&0?'bold':'normal')+'">Filter</a>'; RK_AddClickPref(oFilter, RK_FILTER, RK_ShowSeriesFilter); oSelect.parentNode.insertBefore(oDiv, oSelect.nextSibling); oDiv.appendChild(oSelect); oDiv.appendChild(oFilter); } } } // RK_Addfilter ////////////////////////////////////////////////// function RK_SeriesFilter() { RK_log('RK_SeriesFilter: ' + RK_oPrefs[RK_FILTER]); var aSeries = RK_oGlobals.SeasonListing; if(aSeries) { // var oRacingSeries = RK_GetDropDown(RK_xpath('.//DIV[@id="racingpanel_inner"]')); var oRacingSeries = RK_GetDropDown(RK_xpath('.//DIV[@id="racingpanel_series"]')); var oSeriesSelect = RK_GetDropDown(RK_xpath('.//SELECT[@id="series_select"]')); if(RK_oPrefs[RK_FILTER]) { var oSeriesList = new Object(); for(var i=0; i<aSeries.length; i++) { if(!(oSeriesList[aSeries[i].seriesid]) || !(oSeriesList[aSeries[i].seriesid].active)) oSeriesList[aSeries[i].seriesid] = aSeries[i]; } var oExclude = RK_oPrefs[RK_FILTER_LIST]; for(var i in oExclude) { var oExclude = oSeriesList[i]; if(oExclude) { if(oRacingSeries) RK_RemoveOption(oRacingSeries[oExclude.seasonid]); if(oSeriesSelect) RK_RemoveOption(oSeriesSelect[oExclude.seriesid]); } } // Now, remove the old inactive series for(var nSeries in oSeriesList) { var oSeries = oSeriesList[nSeries]; if(!oSeries.active) { if(oSeriesSelect) RK_RemoveOption(oSeriesSelect[oSeries.seriesid]); } } } RK_Addfilter(oRacingSeries); RK_Addfilter(oSeriesSelect); } } // RK_SeriesFilter ////////////////////////////////////////////////// function RK_Select(xOptions, sValue, sFunction) { RK_log('RK_Select: '+sValue+' : '+xOptions.snapshotLength); if(xOptions.snapshotLength) { // var aOptions = xSelect.snapshotItem(0).childNodes; for(var i=0; i < xOptions.snapshotLength; i++) { var oOption = xOptions.snapshotItem(i); if(oOption.value == sValue && !oOption.selected) { RK_GetParentSelect(oOption).selectedIndex = oOption.index; document.location.href = sFunction; } } } } // RK_Select ////////////////////////////////////////////////// function RK_GetObject(aArray, key, value) { RK_log('RK_GetObject'); for(var i = 0; i < aArray.length; i++) { if(aArray[i][key] == value) { RK_log('RK_GetObject: '+aArray[i][key]); return(aArray[i]); } } } // RK_GetObject ////////////////////////////////////////////////// function RK_SetSelectBoxes() { var aTables = RK_oSelectPages[RK_sPage]; if(aTables) { for(var i=0; i < aTables.length; i++) { RK_WaitForElement(aTables[i], function(xRes, oConfig) { RK_log('RK_SetSelectBoxes'); if(RK_sPage == 'Stats') RK_Select(RK_xpath('.//DIV[@id="careerTabContent"]/*/SELECT//OPTION'), // Personal stats car selection RK_oGlobals['racingpaneldata.car'].id, 'javascript:CareerTab.getPersonalBests('+RK_oGlobals['racingpaneldata.car'].id+','+RK_oGlobals.MemBean.custid+')'); if(RK_sPage == 'Series') RK_Select(RK_xpath('.//SELECT[@id="class_select"]//OPTION'), // Series Stats RK_GetObject(RK_oGlobals.CarClassListing, 'name', RK_oGlobals['racingpaneldata.car'].name).id, 'javascript:ajax_filter(0,active_stat)'); // RK_Select(RK_xpath('.//SELECT[@id="series_select"]//OPTION'), // Planner Widget // RK_oGlobals.racingpaneldata.series.seriesid, // 'javascript:eventPlannerWidget.update_seriesid()'); // RK_Select(RK_xpath('.//SELECT[@id="standings_series_select"]//OPTION'), // Standing Widget // RK_oGlobals.racingpaneldata.series.seriesid, // 'javascript:regionStandingsWidget.handleSeriesSelect()'); }, 1); } window.setTimeout(function() { RK_OnlineFriends(); }, 5000); } } // RK_SetSelectBoxes ////////////////////////////////////////////////// /* function RK_MixedClassStats() { if(RK_oGlobals.racingpaneldata) { RK_log('RK_MixedClassStats'); var aNames = RK_oGlobals.racingpaneldata.car.name.split(/\s+/); var nMax = 0; var xSelect = RK_xpath('.//SELECT[@id="class_select"]'); if(xSelect.snapshotLength) { var aOptions = xSelect.snapshotItem(0).childNodes; for(var i=0; i < aOptions.length; i++) { var nCount = 0; for(var j=0; j < aNames.length; j++) { if(aOptions[i].textContent.match(new RegExp(aNames[j],'i'))) { nCount++; } } if(nCount > nMax && !(aOptions[i].selected)) { nMax = nCount; RK_log('RK_MixedClassStats: Activating: '+aOptions[i].text); aOptions[i].selected = true; } } if(nMax > 0) { var xGo = RK_xpath('.//A[@href="javascript:ajax_filter(0,active_stat)"]'); if(xGo.snapshotLength) { var oGo = xGo.snapshotItem(0); document.location.href = oGo.href; } } } } } // RK_MixedClassStats */ ////////////////////////////////////////////////// function RK_OnlineFriends() { RK_log('RK_OnlineFriends'); var aTables = RK_oFriendPages[RK_sPage]; if(aTables) { for(var i=0; i < aTables.length; i++) { RK_WaitForElement(aTables[i], function(xRes, oConfig) { var fn = oConfig.func || RK_ProcessDrivers; fn(xRes, oConfig); RK_RegisteredFriends(); }); } window.setTimeout(function() { RK_OnlineFriends(); }, 5000); } } // RK_OnlineFriends ////////////////////////////////////////////////// function RK_ProcessRegistered(oDrivers, oDrvSess) { RK_log('RK_ProcessRegistered'); url = RK_sSessionTimesURL; RK_log("RK_ProcessRegistered: " + url); GM_xmlhttpRequest( { method: 'POST', url: url, headers: { "Content-Type": "application/x-www-form-urlencoded" }, onload: function(res) { RK_log("RK_ProcessRegistered: done"); var oSessions = JSON.parse(res.responseText); RK_log(oSessions); var xCell = RK_xpath('//TABLE[@id="sessions_table"]/TBODY/TR/TD'); for(var i = 0; i < oSessions.d.r.length; i++) { var oSession = oSessions.d.r[i]; if(oSession[1] > 0) { RK_log('RK_ProcessRegistered: ' + oSession[1] + " : " + oSession[8]); var aDrivers = oDrvSess[oSession[1]] || new Array(); for(var j = 0; j < aDrivers.length; j++) { var oDriver = aDrivers[j]; RK_log(oDriver); var nCell = RK_oSessionCellLookup[oSession[8]]; var oCell = xCell.snapshotItem(nCell); if(oCell) { RK_log(oCell); var oDiv = RK_xpath('.//DIV[@class="sessiontype_contain"]', oCell).snapshotItem(0); // var oDiv = RK_xpath('.//DIV[@class="sessiontype_contain"]//DIV', oCell).snapshotItem(oDivOffset[nCell]++); if(oDiv) { RK_log(oDiv); RK_log(oDriver); var div = document.createElement('div'); div.id = 'RK_ProcessRegistered'; // div.cssText = 'padding:2px; text-align:left;'; // div.className = ''; div.innerHTML = RK_GetDriverName(oDriver); oDiv.appendChild(div); } } } } } } }); } // RK_ProcessRegistered ////////////////////////////////////////////////// function RK_RegisteredFriends() { RK_log('RK_RegisteredFriends'); if(RK_sPage == 'Sessions' && !document.getElementById('RK_RegisteredFriends')) { window.setTimeout(function() { RK_GetRegistered(RK_ProcessRegistered); }, RK_LoopWait); } } // RK_RegisteredFriends ////////////////////////////////////////////////// function RK_Begin() { RK_log('RK_Begin'); for(var id in RK_oGlobals.FriendsListing) { RK_oIDs[id] = 'stats_friend_tr'; } for(var id in RK_oGlobals.WatchedListing) { RK_oIDs[id] = 'stats_watched_tr'; } if(RK_oPrefs.Self && RK_oGlobals.MemBean) RK_oIDs[RK_oGlobals.MemBean.custid] = 'stats_self_tr'; if(RK_SERIES_FILTER) RK_SeriesFilter(); // var RK_MIXED_CLASS = 0; // (RETIRED) Set to 0 to turn off the automatic Mixed-Class car selection // if(RK_MIXED_CLASS) RK_MixedClassStats(); if(RK_SET_SELECTS) RK_SetSelectBoxes(); if(RK_FRIENDS) RK_OnlineFriends(); } // RK_Begin ////////////////////////////////////////////////// function RK_UpdateCheck() { // Based on: http://userscripts.org/scripts/show/20145 if(!(RK_oPrefs.SkipUpdateCheck)) { RK_log('RK_UpdateCheck'); var now = new Date().getTime(); var last = RK_oPrefs.LastUpdate || 0; var id = 'RK_UPDATE'; var id_toggle = id+'_TOGGLE'; var whatsnewid = 'RK_UPDATE_WHATS_NEW'; if((last + RK_Update) <= now || RK_DEBUG) { try { RK_oPrefs.LastUpdate = now; RK_SetPrefs(); GM_xmlhttpRequest( { method: 'GET', url: 'http://userscripts.org/scripts/source/'+RK_Script+'.meta.js?'+now, headers: {'Cache-Control': 'no-cache'}, onload: function(resp) { var res = resp.responseText; if(res) { var aVer = res.match(/@version\s*(.*?)\s*$/m); var aName = res.match(/@name\s*(.*?)\s*$/m); RK_log('RK_UpdateCheck: Site Ver: '+aVer); RK_log('RK_UpdateCheck: Local Ver: '+RK_Version); if((aVer && aVer[1] != RK_Version) || RK_DEBUG) { var div = document.createElement('div'); div.id = id; div.className = 'stats_friend_tr'; div.style.cssText = 'position:absolute; left:200px; top:380px; border:2px solid #000000; z-index:'+(RK_Z++)+'; padding:3px; text-align:left;'; var html = ''; html += '<div>There is a new version of "<b>iRacing Online Friends</b>".</div>'; html += '<div>Please visit the <a target="_blank" href="http://userscripts.org/scripts/show/'+RK_Script+'">UserScript page '+RK_ImgPop+'</a> to upgrade.</div>'; html += '<div id="'+whatsnewid+'"></div>'; html += '<br><div>Or, visit the <a target="_blank" href="http://members.iracing.com/jforum/posts/list/1275006.page">iRacing Forum thread '+RK_ImgPop+'</a> for more info.</div>'; html += '<br><a id="'+id_toggle+'" onclick="return(false);" href="">Turn off update checks</a>'; html += '<div style="text-align:right; float:right;"><a href="" onclick="javascript:document.getElementById(\''+id+'\').style.display=\'none\'; return(false);">Close [X]</a></div>'; div.innerHTML = html; var child = document.body.firstChild; if(child) { child.parentNode.insertBefore(div, child); } RK_AddClickPref(document.getElementById(id_toggle), 'SkipUpdateCheck'); } } GM_xmlhttpRequest( { method: 'GET', url: 'http://www.kodey.com/iRacing/iracing_online_friends.html', headers: {'Cache-Control': 'no-cache'}, onload: function(resp) { var msg = resp.responseText; var div = document.getElementById(whatsnewid); if(div && msg) { div.innerHTML = msg; } } }); } }); } catch (err){} } } } // RK_UpdateCheck ////////////////////////////////////////////////// var RK_oGlobalElem = document.createElement('div'); RK_oGlobalElem.id = "RK_oGlobalElem"; RK_oGlobalElem.style.visibility = "hidden"; RK_oGlobalElem.style.display = "none"; document.body.appendChild(RK_oGlobalElem); ////////////////////////////////////////////////// function RK_WaitForGlobals(func, count) { RK_log('RK_WaitForGlobals'); if(!count) count = 1; var ret = RK_oGlobalElem.innerHTML; if(!ret) { if(count < RK_MaxLoops) window.setTimeout(function() { RK_WaitForGlobals(func, count+1); }, RK_LoopWait); } else { RK_oGlobals = JSON.parse(ret); RK_log(RK_oGlobals); func(); } } // RK_WaitForGlobals ////////////////////////////////////////////////// function RK_SetGlobal(name, val) { document.location.href = 'javascript:void('+name+'='+JSON.stringify(val)+')'; } // RK_SetGlobal ////////////////////////////////////////////////// function RK_GetGlobals(aVars, func) { var js = 'javascript:(function(){var x={};var a=function(v){x[v]=eval(v)};'; for(var i=0; i < aVars.length; i++) { var name = aVars[i]; js += 'a("'+name+'");'; } js += 'document.getElementById("RK_oGlobalElem").innerHTML=JSON.stringify(x);void(0);})()'; RK_log('RK_GetGlobals: '+js.length+': '+js); document.location.href = js; RK_WaitForGlobals(func); } // RK_GetGlobals ////////////////////////////////////////////////// var RK_oSelectPages = { Stats : [ { name: 'personalBestsTable', type: 'id' } ], Series : [ { name: 'stats_series_table', type: 'class' } ] }; var RK_oFriendPages = { Dashboard : [ { name: 'WHPracticeTable', type: 'id', nSpanL: 2, nSpanR: 5, url: RK_sOpenSessionURL }, { name: 'WHEventsTable', type: 'id', nSpanL: 4, nSpanR: 5, url: RK_sCustDisplayURL }, { name: 'WHRaceTable', type: 'id', nSpanL: 2, nSpanR: 5, url: RK_sOpenSessionURL, func: RK_RaceRegistered } ], Sessions : [ { name: 'openpractice_table', type: 'id', nSpanL: 1, nSpanR: 3, url: RK_sOpenSessionURL } ], Join : [ { name: 'hosted_sessions_current',type: 'id', nSpanL: 9, nSpanR: 6, url: RK_sPrivateSessionURL, func: RK_ProcessHosted } ], Hosted : [ { name: 'results_table', type: 'class', nSpanL: 9, nSpanR: 4, url: RK_sCustDisplayURL } ], Results : [ { name: 'Results-Table', type: 'id', nSpanL: 10, nSpanR: 4, url: RK_sCustDisplayURL } ], SeriesResults: [ { name: 'series_results_table', type: 'class', nSpanL: 4, nSpanR: 4, url: RK_sCustDisplayURL } ], Spectator : [ { name: 'spectator_table', type: 'class', nSpanL: 3, nSpanR: 5, url: RK_sSessionDriversURL, reZero: /[>(]\s*0\s*[)<]/ } ], Replays : [ { name: 'replays_data_table', type: 'class', nSpanL: 10, nSpanR: 8, url: RK_sCustDisplayURL } ], Stats : [ { name: 'last10_table', type: 'class', nSpanL: 7, nSpanR: 5, url: RK_sCustDisplayURL } ] }; // RK_oFriendPages ////////////////////////////////////////////////// RK_sPage = RK_oURLs[document.location.pathname.toLowerCase()]; if(RK_sPage == 'Home') if(document.title.match(/Dashboard/i)) RK_sPage = 'Dashboard'; // if(RK_sPage == 'Stats') // { // if(document.location.href.match(/friendid=/i)) RK_sPage = 'Friends' // else if(document.location.href.match(/watchedid=/i)) RK_sPage = 'Studied' // else if(document.location.href.match(/custid=/i)) RK_sPage = 'Drivers' // else RK_sPage = 'Personal' // } RK_log('RK_sPage: ' + RK_sPage); // RK_SetGlobal('ajaxUpdateManager.freqs.whpractice', 300); RK_GetGlobals([ 'MemBean', 'FriendsListing', 'WatchedListing', 'racingpaneldata.car', 'SeasonListing', 'simStatus', 'CarClassListing'], RK_Begin); RK_UpdateCheck(); //@ sourceURL=OnlineFriends.js