Here is the source from a ss viewer that does work for all games but I hate the layout and gui....that's why I was attempting to create my own.
But can you check the code for me as I am unsure what's "clean & secure" code and what's not. Are your examples better than the code below?
Thanks for all the suggestions guys!
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<!-----------------------------------------
Main Stream Gamers PunkBuster Screenshot Viewer
An original work by Bruce "Goose" Kaskubar
Licensed under GPL v3
http://www.msgamers.com
--------------------------------------- -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>MSGPBSSV: MSG's PunkBusterβ’ Screenshot Viewer</title>
<style type="text/css">
a { text-decoration:none; color:#00F; }
a:hover { color: #FFF; background-color: #009; }
a.white { color:#FFF; }
a.white:hover { background-color: #FFF; color:#565; }
td a { display: block; }
tr { vertical-align:top; }
html { height:99%; }
.footer { background-color:#787; height:1.4em; font-size:80%;}
.invisible { visibility:hidden; height:0px; }
.ss { color:#933; font-weight:bold; }
.small { font-size:90%; font-weight:normal; }
.thorax { background-color:#EEE; }
.title { background-color:#787; height:1.4em; font-weight:bold; }
#nav ul { margin:0 0 0 0; padding:0 0 0 0; list-style:none; }
#nav ul li a { display:block; text-decoration:none; height: 1.3em; }
</style>
</head>
<body style="background-color:#ABA; font-family:Verdana, Arial, Helvetica, sans-serif; height:100%;">
<!---------------------------------------
HEADER
------------------------------------- -->
<div style="height:3%;">
<a href="http://deadendgaming.net">
<img alt="DEAD END GAMING" height="94" src="http://deadendgaming.net/images/d3g_email_logo.png" width="500" /></a>
<span class="small" style="float:right;">By: MSG version <span id="versionNum">1.06</span></span></div>
<!---------------------------------------
LEFT SIDE
------------------------------------- -->
<div style="float:left; width:29em; margin:4px 0px 4px 0px;">
<div class="title">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>Settings</td>
<td align="right" class="small" style="cursor:pointer;"><div id="hideSettings" style="display:none;"><a onclick="javascript:document.getElementById('settings').style.display ='none';document.getElementById('hideSettings').style.display ='none';document.getElementById('showSettings').style.display ='';">hide</a></div><div id="showSettings"><a onclick="javascript:document.getElementById('settings').style.display ='';document.getElementById('showSettings').style.display ='none';document.getElementById('hideSettings').style.display ='inline';">show</a></div></td>
</tr>
</table>
</div>
<div class="thorax" style="height:auto; overflow:auto; display:none;" id="settings">
<form name="settings">
<input name="pbss" type="checkbox" />
Display screenshots in <a href="http://www.aliasfinder.co.uk/products/pbss/index.htm" target="msgx">PBSS plugin</a>
<select name="pbssw"><option>400</option><option>500</option><option selected="selected">600</option><option>700</option><option>800</option></select>
x
<select name="pbssh"><option>300</option><option selected="selected">400</option><option>500</option><option>600</option></select>
<input type="radio" name="timeFormatInd" value="0" checked="checked" onclick="TFx=this.value;"/>12-hour time
<input type="radio" name="timeFormatInd" value="1" onclick="TFx=this.value;"/>24-hour time
</form>
</div>
<div id="navTitle" class="title" style="margin-top:8px;">List Selection</div>
<div id="nav" class="thorax">
<ul>
<li><a href="javascript:showXsummary();">Index Summary</a></li>
<li><a href="javascript:showPlayersWithAliases();">Players With Aliases</a></li>
<li><a href="javascript:showPlayerSScensus('Screenshot Census by Player, all','1');">Screenshot Census by Player, all</a></li>
<li><a href="javascript:showPlayerSScensus('Screenshot Census by Player, >0','Players[i].ssCnt >0');">Screenshot Census by Player, >0</a></li>
<li><a href="javascript:showScreenshotCensusByTime(15);">Screenshot Census by 15 Minute Periods</a></li>
</ul>
</div>
<div id ="listTitle" class="title" style="margin-top:8px;"></div>
<div id="list" class="thorax" style="height:256px; overflow:auto;">loading PunkBuster's screenshot index...</div>
<div id="listFooter" class="footer"></div>
<div style="height:auto; margin-top:8px;">
<div id="detailsTitle" class="title" style="height:auto;"></div>
<div id="details" class="thorax" style="height:auto; overflow:auto;"></div>
</div>
</div>
<!---------------------------------------
RIGHT SIDE
------------------------------------- -->
<div id="screenshots" style="float:right; background-color:#EEE; margin:4px 4px 4px 4px; height:92%; width:auto;">
<div id="ssTitle" class="title"></div>
<div id="ss" class="small" style="height:97%; overflow:auto;"></div>
</div>
<!---------------------------------------
FOOTER
------------------------------------- -->
<div style="clear:both; background-color:#565; height:4%;" class="small">
<table style="color:#FFF; width:100%;">
<tr>
<td width="33%"><a href="http://anticheatinc.net">ACI WEBSITE</a> <a href="http://www.pbbans.com">PBBANS WEBSITE</a></td>
<td width="34%" align="center"><a href="http://deadendgaming.net">D3G
WEBSITE</a></td>
<td width="33%" align="right"><a href="http://www.msgamers.com/smf/index.php?board=23.0" target="msgx" class="white">Viewer forum</a></td>
</tr>
<tr><td colspan="3" align="center" style="color:#DDD;"><script>m=/.*\/\/(.+).+)@(.+)/.exec(document.URL);document.write((m===null)?document.URL:m[3]);</script></td></tr>
</table>
</div>
<!---------------------------------------
CONTENT LOADER
------------------------------------- -->
<iframe src="pbsvss.htm" name="loader" onload="parsePBSV(this);" class="invisible" style="color:#963; font-weight:bold;">Sorry, the Viewer uses inline frames and your browser does not support them.</iframe>
</body>
<script type="text/javascript">
//-----------------------------------
// Globals
//-----------------------------------
var MOTY =["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
var DOTW =["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
var TF =[["h:i a", "h:i:s a"], ["H:i", "H:i:s"]];
var TFx =0; // default time format
var linesFoundCnt =0; // number of entries in index
var linesLoadedCnt =0; // number of index entries imported
var excludedLines =new Array(); // skipped PB index entries
// [0]: reason index
// [1]: the excluded line
var exclusionReasons =[
'player name could not be found',
'line item format was nonstandard'
];
var earliestItemTS =-1;// PB line item timestamp range
var latestItemTS =-1; // PB line item timestamp range
var pwssCnt =0; // players with screenshots
var maxPSScnt =0; // highest number of screenshots for a single player (name & GUID)
var maxTSScnt =0; // highest number of screenshots for a single time period
function parsePBSV(f) { // create Viewer objects from PB index found in frame f
var x =frames[f.getAttribute('name')].document;
var p =x.getElementsByTagName('p');
linesFoundCnt =p.length;
for (i =0; i <p.length; i++) importItem(p[i].innerHTML);
document.getElementById('list').innerHTML ="calculating statistics...";
setTimeout("calcStats()", 256);
}
function importItem(l) { // import PB line item l
var m =ssRE.exec(l);
if (m ===null) { excludedLines.push([1, l]); return; }
var ts =new Date(m[7], m[8] -1, m[9], m[10], m[11], m[12], 0);
addScreenshot(m[2], addPlayer(m[3], m[5], ts).OID, ts, m[1]);
linesLoadedCnt++;
}
function calcStats () {
pwssCnt =thePlayerCensus('Players[i].ssCnt >0');
for (i in Players) if (Players[i].ssCnt >maxPSScnt) maxPSScnt =Players[i].ssCnt;
document.getElementById('list').innerHTML ="sequencing player names...";
setTimeout("sequencePlayers()", 256);
}
function sequencePlayers () {
var i, p, s =new Array();
for (i in Players) s.push(Players[i]);
s.sort(function (a, b) {
if (a.sortNm > b.sortNm) return 1;
if (a.sortNm < b.sortNm) return -1;
return 0;
});
if (s.length >0) {
PlayerAOID =s[0].OID;
PlayerZOID =s[s.length -1].OID;
for (i =0; i <s.length; i++) { // build player linked list
p =getPlayerByOID(s[i].OID);
if (i >0) p.prevOID =s[i -1].OID;
if (i <s.length -1) p.nextOID =s[i +1].OID;
}
}
showXsummary();
}
function showXsummary () {
// present the PB index file summary
document.getElementById('listTitle').innerHTML ='Index Summary';
document.getElementById('list').innerHTML =
'<table cellpadding="3" cellspacing="0">'
+'<tr><td>items encountered:</td><td>' +fix(linesFoundCnt) +'</td></tr>'
+'<tr><td>items loaded:</td><td>' +fix(linesLoadedCnt) +'</td></tr>'
+'<tr><td><acronym title="index entries not elsewhere included due to noncompliance with expected format">items excluded</acronym>:</td><td><a href="javascript:showExcludedLines();">' +fix(excludedLines.length) +'</a></td></tr>'
+'<tr><td>from:</td><td>' +((earliestItemTS ==-1) ? '' : theDT(earliestItemTS, 'D dMy ' +TF[TFx][1])) +'</td></tr>'
+'<tr><td>through:</td><td>' +((latestItemTS ==-1) ? '' : theDT(latestItemTS, 'D dMy ' +TF[TFx][1])) +'</td></tr>'
+'<tr><td>players:</td><td>' +fix(thePlayerCnt()) +'</td></tr>'
+'<tr><td>screenshots:</td><td>' +fix(theSSCnt()) +'</td></tr>'
+'<tr><td>players<br>w/screenshots:</td><td><br>' +fix(pwssCnt) +'</td></tr>'
+'<tr><td><acronym title="average (mean) screenshot count among players with screenshots" >screenshots<br>/player</acronym>:</td><td><br>' +((pwssCnt ==0) ? 'quite meaningless' : fix(Math.round(theSSCnt() /pwssCnt))) +'</td></tr>'
+'</table>';
document.getElementById('listFooter').innerHTML ='';
}
function showExcludedLines() {
// present details of non-imported index entries
document.getElementById('ssTitle').innerHTML ='Excluded Index Entries';
var i, s, m, s2;
var d ='<table cellpadding="3" cellspacing="0">';
for (i =0; i <excludedLines.length; i++) {
m =ssX.exec(excludedLines[i][1]);
if (m ===null) s ='[The line is so bad it could not be formatted for display.]';
else s =m[1] +' ' +m[2];
s2 =excludedLines[i][1].replace(/'/g, """); // escape excluded line's single and double quotes
s2 =s2.replace(/"/g, """);
d +='<tr>'
+'<td align="right">' +(i +1) +' of ' +excludedLines.length +'</td>'
+'<td><a href="javascript:alert(\'' +s2 +'\');">' +s +'</a></td>'
+'</tr>';
}
d +='</table>';
document.getElementById('ss').innerHTML =d;
}
//-----------------------------------
// Player class and methods
//-----------------------------------
var Players =new Array(); // object store; key is OID
var PlayersXng =new Object(); // Players index; key is name and GUID, value is OID
var PlayersXg =new Object(); // Players index; key is GUID, value is array of OIDs
var PlayersS =new Array(); // Players index; key is name, value is OID; in ascending sequence by name
var PlayerAOID =-1; // OID of first player in sequence
var PlayerZOID =-1; // OID of last player in sequence
function Player (o, n, g, t) {
this.OID =o; // unique identifier
this.name =n; // name
this.GUID =g; // Activision ID
this.ssCnt =0; // screenshot count
this.firstXts =t; // earliest indexed screenshot timestamp
this.lastXts =t; // latest indexed screenshot timestamp
this.sortNm =theSortNm(n);// key for sorting by name
this.prevOID=-1; // previous player in ascending sequence
this.nextOID=-1; // next player in ascending sequence
}
function addPlayer (n, g, t) {
// if not present, add Player with name n, guid g, and screenshot timestamp t; maintain indexes
// return Player object
if ((n +',' +g) in PlayersXng) {
if (Players[PlayersXng[n +',' +g]].firstXts >t) Players[PlayersXng[n +',' +g]].firstXts =t;
if (Players[PlayersXng[n +',' +g]].lastXts <t) Players[PlayersXng[n +',' +g]].lastXts =t;
return Players[PlayersXng[n +',' +g]];
}
Players.push(new Player(Players.length, n, g, t));
PlayersXng[n +',' +g] =Players.length -1;
if (g in PlayersXg) {} else PlayersXg[g] =[];
PlayersXg[g].push(Players.length -1);
return Players[Players.length -1];
}
function getPlayerAliases (g, n, c) {
// return list of names used by Player whose GUID is g except for name n for criteria c;
var d ="";
for (var i in PlayersXg[g]) if (Players[PlayersXg[g][i]].name !=n)
d
+='<a href="javascript:showPlayerDetails('
+Players[PlayersXg[g][i]].OID
+', \'' +c +'\')">'
+theDisplayNm(Players[PlayersXg[g][i]].name)
+'</a>';
return d;
}
function getPlayerByOID (o) {
// return the Player whose OID is o, or null;
return Players[o];
}
function showPlayerDetails (o, c) {
// show details of player whose OID is o matching criteria c
var gpa =getPlayerAliases(Players[o].GUID, Players[o].name, c);
if (gpa <='') gpa ='[none]';
var d =
'<table cellpadding="0" cellspacing="0" width="100%"><tr>'
+'<td>Player Details</td>'
+'<td align="right"><input type="button" value="';
if (Players[o].prevOID >=0) d +='<" onclick="showPlayerDetails(' +Players[o].prevOID +', \'' +c +'\')">';
else d +=' ">';
d +=' <input type="button" value="';
if (Players[o].nextOID >=0) d +='>" onclick="showPlayerDetails(' +Players[o].nextOID +', \'' +c +'\')';
else d +=' ';
d +=
'"></td>'
+'</tr></table>';
document.getElementById('detailsTitle').innerHTML =d;
var spd =
'<table cellpadding="2" cellspacing="0" width="100%">'
+'<tr>'
+'<td><acronym title="name without color codes">name:</acronym></td>'
+'<td colspan="2">' +theDisplayNm(Players[o].name) +'</td>'
+'</tr>'
+'<tr>'
+'<td><acronym title="name as entered in Multiplayer Options, including color codes">real name</acronym>:</td><td colspan="2">' +Players[o].name +'</td>'
+'</tr>'
+'<tr>'
+'<td><acronym title="other players with the same GUID">aliases</acronym>:</td>'
+'<td colspan="2">' +gpa +'</td>'
+'</tr>'
+'<tr>'
+'<td>GUID:</td>'
+'<td colspan="2">' +Players[o].GUID +'</td>'
+'</tr>'
+'<tr>'
+'<td><acronym title="time of first reference in index">earliest</acronym>:</td>'
+'<td colspan="2">' +theDT(Players[o].firstXts, 'D dMy ' +TF[TFx][1]) +'</td>'
+'</tr>'
+'<tr>'
+'<td><acronym title="time of last reference in index">latest</acronym>:</td>'
+'<td colspan="2">' +theDT(Players[o].lastXts, 'D dMy ' +TF[TFx][1]) +'</td>'
+'</tr>'
+'<tr>'
+'<td>screenshots:</td>'
+'<td colspan="2"><a href="javascript:showScreenshots(\'Screenshots from ' +theDisplayNm(Players[o].name) +'\', \'Screenshots[i].playerOID ==' +o +'\');">' +Players[o].ssCnt +'</a></td>'
+'</tr>';
// build an array of screenshots from this player
var s =new Array(), i;
for (i in Screenshots) if (Screenshots[i].playerOID ==o) s.push(Screenshots[i]);
s.sort(function (a, b) { return a.dtm -b.dtm; } );
// build an array of days for which the player has screenshots
var s2 =new Array(), d, cnt, maxCnt =0, t=new Date();
for (i =0; i <s.length;) {
d =new Date(s[i].dtm.getFullYear(), s[i].dtm.getMonth(), s[i].dtm.getDate(), 0, 0, 0).valueOf();
cnt =0;
while (i <s.length && s[i].dtm.valueOf() <d +1000*60*60*24) {
cnt++;
i++;
}
s2.push(new Array(d, cnt));
if (cnt >maxCnt) maxCnt =cnt;
}
// emit the daily line items
if (s2.length >0) {
spd +=
'<tr style="background-color:#CCC;">'
+'<td colspan="3">Screenshots by Day</td>'
+'</tr>';
spd +='<div style="max-height:256px;">';
for (i =0; i <s2.length; i++) {
spd +=
'<tr>'
+'<td>'
+'<a href="javascript:showPeriodDetails(' +s2[i][0] +',' +(s2[i][0] +1000*60*60*24) +');">'
+theDT(new Date(s2[i][0]), 'D dMy')
+'</a>'
+'</td>'
+'<td align="right">'
+'<a href="javascript:showScreenshots(\'Screenshots from '
+theDisplayNm(Players[o].name)
+'\', \'Screenshots[i].playerOID=='
+o +'&&Screenshots[i].dtm>=' +s2[i][0] +'&&Screenshots[i].dtm<' +(s2[i][0] +1000*60*60*24) +'\');">'
+s2[i][1]
+'</a>'
+'</td>'
+'<td width="40%">' +theLine(s2[i][1], maxCnt) +'</td>'
+'</tr>';
}
spd +='</div>';
}
document.getElementById('details').innerHTML =spd +'</table>';
}
function showPlayerSScensus (t, c) {
// return list of player SS links entitled t for players meeting criteria c
document.getElementById('listTitle').innerHTML =t;
var tpl =
'<tr style="background-color:#CCC;">'
+'<td>Name</td>'
+'<td align="right">Count</td>'
+'<td width="40%"> </td>'
+'</tr>';
var itemCnt =0;
var i =PlayerAOID;
while (i >=0) {
if (eval(c)) {
itemCnt++;
tpl +='<tr>'
+'<td>'
+'<a href="javascript:showPlayerDetails('
+Players[i].OID +', \'' +c +'\');">'
+theDisplayNm(Players[i].name)
+'</a>'
+'</td>'
+'<td align="right">'
+'<a href="javascript:showScreenshots(\'Screenshots from '
+theDisplayNm(Players[i].name)
+'\', \'Screenshots[i].playerOID =='
+Players[i].OID +'\');">'
+Players[i].ssCnt
+'</a>'
+'</td>'
+'<td>' +theLine(Players[i].ssCnt, maxPSScnt) +'</td>'
+'</tr>';
}
i =Players[i].nextOID;
}
document.getElementById('list').innerHTML =
'<table cellpadding="2" cellspacing="0" width="100%">'
+tpl
+'</table>';
document.getElementById('listFooter').innerHTML =itemCnt +' players';
}
function showPlayersWithAliases () {
// return list of players with aliases
document.getElementById('listTitle').innerHTML ='Players With Aliases';
var s =new Array(), i;
for (i in Players) if (PlayersXg[Players[i].GUID].length >1) s.push(Players[i]);
s.sort(function (a, b) {
if (a.sortNm > b.sortNm) return 1;
if (a.sortNm < b.sortNm) return -1;
return 0;
});
var d =
'<tr style="background-color:#CCC;">'
+'<td width="50%">Name</td>'
+'<td width="50%">Aliases</td></tr>';
for (i in s) {
d +='<tr><td><a href="javascript:showPlayerDetails('
+s[i].OID +', \'1\');">'
+theDisplayNm(s[i].name)
+'</a></td>'
+'<td>' +getPlayerAliases(s[i].GUID, s[i].name, '1')
+'</a></td></tr>';
}
document.getElementById('list').innerHTML =
'<table cellpadding="2" cellspacing="0" width="100%">'
+d
+'</table>';
document.getElementById('listFooter').innerHTML =fix(s.length) +' players';
}
function theDisplayNm (n) {
// return the display name for name n
var tdn =n;
var re = /\^\d/; // replace color codes
while (re.test(tdn)) tdn = tdn.replace(re, '');
var re = /\</; // replace opening brackets
while (re.test(tdn)) tdn = tdn.replace(re, '<');
var re = /\>/; // replace closing brackets
while (re.test(tdn)) tdn = tdn.replace(re, '>');
return tdn;
}
function thePlayerCnt () { return Players.length; }
function thePlayerCensus (c) {
// return count of players matching criteria c
var cnt =0;
for (i in Players) if (eval(c)) cnt++;
return cnt;
}
function theSortNm (n) {
// return the sort key for name n
var tsn =n;
var re = /\^\d|\W|_/g; // remove special characters
while (re.test(tsn)) tsn = tsn.replace(re, '');
return tsn.toUpperCase();
}
function updatePlayerSSCnt(o, a) {
// add a to screenshot count of Player whose OID is o
// return the new count
Players[o].ssCnt +=a;
return Players[o].ssCnt;
}
//-----------------------------------
// Screenshot classes and methods
//-----------------------------------
var Screenshots =new Array(); // object store; key is OID
var ScreenshotsXf =new Object(); // Screenshots index; key is file name, value is OID
var ssID =0; // viewed screenshot sequence number (used as global instead of local because some browsers' DOM methods refuse to recognize an object whose ID matches that of a previously deleted object)
var SSrequests =new Array(); // screenshot request queue object store
var ssTm1, ssTm2;
function Screenshot (o, s, p, t, f) {
this.OID =o; // unique identifier
this.seqNo =s; // PB sequence number
this.playerOID =p; // a Player.OID
this.dtm =t; // PB ss time stamp
this.fileNm =f; // PB ss HTML file name
}
function SSrequest (i, f, tr, tc) {
this.ssID =i; // ss identifier
this.fileNm =f; // ss file name
this.addDT =0; // request add time
this.startDT =tr; // request start time
this.compDT =tc; // request completion time
}
function addScreenshot (s, p, t, f) {
// add screenshot with sequence number s, player OID p, timestamp t, and file name f
// if its file is already recorded, update the existing ss entry
if (t <earliestItemTS || earliestItemTS ==-1) earliestItemTS =t;
if (t >latestItemTS || latestItemTS ==-1) latestItemTS =t;
if (f in ScreenshotsXf) { // overlay prior entry
Screenshots[ScreenshotsXf[f]].seqNo =s;
updatePlayerSSCnt(Screenshots[ScreenshotsXf[f]].playerOID, -1); // decrease count for overridden player
Screenshots[ScreenshotsXf[f]].playerOID =p;
updatePlayerSSCnt(p, 1);
Screenshots[ScreenshotsXf[f]].dtm =t;
return;
}
Screenshots.push(new Screenshot(Screenshots.length, s, p, t, f));
ScreenshotsXf[f] =Screenshots.length -1;
updatePlayerSSCnt(p, 1);
}
function loadSS() { // retrieve next SS in queue
if (SSrequests.length <1) return; // prevent the last screenie from requesting another one
var ss =SSrequests.pop();
f =document.getElementById(ss.ssID);
f.src =ss.fileNm;
// Why go to all this trouble, instead of just setting each iFrame's SRC parameter from the get go?
// There's no difference for local file access. For FTP access, all the screenies would be requested at practically the same time.
// Most FTP servers get fed up with that rush of activity and start refusing connections. Error messages ensue.
// By queueing the file loads, the total load time increases but at least we tend to get all the files.
}
function showScreenshots(t, c) { // return list of screenshots entitled t that meet criteria c
var s =new Array(), i, f;
document.getElementById('ssTitle').innerHTML =t;
for (i in Screenshots) if (eval(c)) s.push(Screenshots[i]);
s.sort(function (a, b) { return a.dtm -b.dtm; } );
var d =''; SSrequests.length =0;
for (i =0; i <s.length; i++) {
d +='<tr>'
+'<td><p class="small">'
+(i +1) +' of ' +s.length
+'<br />'
+'<a href="javascript:showPlayerDetails(' +s[i].playerOID +', ' +'\'1\');">'
+theDisplayNm(getPlayerByOID(s[i].playerOID).name)
+'</a>'
+theDT(s[i].dtm, 'D dMY')
+'<br />'
+theDT(s[i].dtm, TF[TFx][1])
+'<br />'
+s[i].fileNm
+'</p></td>'
+'<td>'
+'<div class="ss"></div>'
+'<iframe id="ss' +ssID +'" name="ss' +ssID +'" class="invisible" onload="showSS(this);"></iframe>'
+'</td>'
+'</tr>';
SSrequests.push(new SSrequest("ss" +ssID, s[i].fileNm, 0, 0));
ssID++;
}
document.getElementById('ss').innerHTML ='<table cellpadding="2" cellspacing="2">' +d +'</table>';
SSrequests.reverse(); // process as a queue, not a stack
loadSS(); // get first SS
}
function showSS (f) { // show screenshot loaded by frame f
if (f.getAttribute('src') <='') return; //skip loads prior to setting src parameter
if (!document.forms.settings["pbss"].checked || frames[f.getAttribute('name')].document.images.length !=1)
f.previousSibling.innerHTML =frames[f.getAttribute('name')].document.body.innerHTML;
else {
f.previousSibling.innerHTML ='<embed'
+' src="' +frames[f.getAttribute('name')].document.images[0].src +'"'
+' gamma="1.5"'
+' image="' +frames[f.getAttribute('name')].document.images[0].src +'"'
+' pluginspage="http://www.aliasfinder.co.uk/products/pbss/files/nppbss.dll"'
+' type="application/x-png-pbss"'
+' width="' +document.forms.settings["pbssw"].value +'"'
+' height="' +document.forms.settings["pbssh"].value +'"'
+'></embed>'
}
loadSS(); // get next SS
}
function showScreenshotsForPeriod(t1, t2) {
// present the screenshots from time t1 to time t2
var dt1 =new Date(t1);
var dt2 =new Date(t2);
showScreenshots('Screenshots from ' +theDT(dt1, 'dMy ' +TF[TFx][0]) +' to ' +theDT(dt2, 'dMy ' +TF[TFx][0]), 'Screenshots[i].dtm >=' +t1 +' && Screenshots[i].dtm <' +t2)
}
function showScreenshotCensusByTime (m) {
// present screenshot list by periods of m minutes
var mInt =parseInt(m);
document.getElementById('listTitle').innerHTML ='Screenshot Census by '
+'<select onchange="showScreenshotCensusByTime(this[selectedIndex].text);">'
+'<option' +((mInt ==1) ? ' selected="selected"' : '') +'>1</option>'
+'<option' +((mInt ==5) ? ' selected="selected"' : '') +'>5</option>'
+'<option' +((mInt ==10) ? ' selected="selected"' : '') +'>10</option>'
+'<option' +((mInt ==15) ? ' selected="selected"' : '') +'>15</option>'
+'<option' +((mInt ==20) ? ' selected="selected"' : '') +'>20</option>'
+'<option' +((mInt ==30) ? ' selected="selected"' : '') +'>30</option>'
+'<option' +((mInt ==60) ? ' selected="selected"' : '') +'>60</option>'
+'</select>'
+' Minute Periods';
var s =new Array(), i, p, pNext;
for (i in Screenshots) s.push(Screenshots[i]);
s.sort(function (a, b) { return (a.dtm -b.dtm) });
var d =
'<tr style="background-color:#CCC;">'
+'<td>Period Start</td>'
+'<td align="right">Count</td>'
+'<td width="40%"> </td>'
+'</tr>';
if (s.length >0) { // find maximum number of screenies in a period
var p =new Date(s[0].dtm.getFullYear(), s[0].dtm.getMonth(), s[0].dtm.getDate(), s[0].dtm.getHours(), Math.floor(s[0].dtm.getMinutes() /mInt) *mInt, 0, 0); // start time of census period
var pNext =new Date(p.getFullYear(), p.getMonth(), p.getDate(), p.getHours(), p.getMinutes() +mInt, 0, 0); // start time of next census period
}
var ssCnt =0;
maxTSScnt =0;
for (i =0; i <s.length; i++) {
if (s[i].dtm <pNext) { ssCnt++; continue; } // count screenies in this period
if (ssCnt >maxTSScnt) maxTSScnt =ssCnt;
p =new Date(s[i].dtm.getFullYear(), s[i].dtm.getMonth(), s[i].dtm.getDate(), s[i].dtm.getHours(), Math.floor(s[i].dtm.getMinutes() /mInt) *mInt, 0, 0);
pNext =new Date(p.getFullYear(), p.getMonth(), p.getDate(), p.getHours(), p.getMinutes() +mInt, 0, 0);
ssCnt =1;
}
if (ssCnt >maxTSScnt) maxTSScnt =ssCnt;
if (s.length >0) {
var p =new Date(s[0].dtm.getFullYear(), s[0].dtm.getMonth(), s[0].dtm.getDate(), s[0].dtm.getHours(), Math.floor(s[0].dtm.getMinutes() /mInt) *mInt, 0, 0); // start time of census period
var pNext =new Date(p.getFullYear(), p.getMonth(), p.getDate(), p.getHours(), p.getMinutes() +mInt, 0, 0); // start time of next census period
}
var ssCnt =0, pCnt =0;
for (i =0; i <s.length; i++) {
if (s[i].dtm <pNext) { ssCnt++; continue; } // count screenies in this period
d +=theSSCBTline(p, pNext, ssCnt);
p =new Date(s[i].dtm.getFullYear(), s[i].dtm.getMonth(), s[i].dtm.getDate(), s[i].dtm.getHours(), Math.floor(s[i].dtm.getMinutes() /mInt) *mInt, 0, 0);
if (p.toString() !=pNext.toString()) d +='<tr><td> </td><td> </td></tr>'; // show gap in time
pNext =new Date(p.getFullYear(), p.getMonth(), p.getDate(), p.getHours(), p.getMinutes() +mInt, 0, 0);
ssCnt =1; pCnt++;
}
if (ssCnt >0) {
d +=theSSCBTline(p, pNext, ssCnt);
pCnt++;
}
document.getElementById('list').innerHTML ='<table cellpadding="2" cellspacing="0" width="100%">' +d +'</table>';
document.getElementById('listFooter').innerHTML =fix(pCnt) +' period' +((pCnt !=1) ? 's' : '');
}
function theSSCBTline(t1, t2, c) {
// return a formatted line for the screenshot census
return '<tr>'
+'<td><a href="javascript:showPeriodDetails(' +t1.valueOf() +', ' +t2.valueOf() +')">' +theDT(t1, 'D dMy ' +TF[TFx][0]) +'</a></td>'
+'<td align="right">'
+'<a href="javascript:showScreenshotsForPeriod(' +t1.valueOf() +', ' +t2.valueOf() +')">' +fix(c) +'</a>'
+'</td>'
+'<td>' +theLine(c, maxTSScnt) +'</td>'
+'</tr>';
}
function theSSCnt () { return Screenshots.length; }
//-----------------------------------
// Time Period classes and methods
//-----------------------------------
function showPeriodDetails (t1, t2) {
// show details of time period starting at time t1 and ending just before time t2
document.getElementById('detailsTitle').innerHTML =
'<table cellpadding="0" cellspacing="0" width="100%">'
+'<tr>'
+'<td>Time Period Details</td>'
+'<td align="right">'
+'<input type="button" value="<" onclick="showPeriodDetails(' +(t1 -(t2 -t1)) +', ' +t1 +')">'
+' '
+'<input type="button" value=">" onclick="showPeriodDetails(' +t2 +', ' +(t2 +(t2 -t1)) +')">'
+'</td>'
+'</tr>'
+'</table>';
// build an array of screenshots for the time period sequenced by player name
var s =new Array(), i;
for (i in Screenshots) if (Screenshots[i].dtm.valueOf() >=t1 && Screenshots[i].dtm.valueOf() <t2) s.push(Screenshots[i]);
s.sort(function (a, b) {
if (Players[a.playerOID].sortNm > Players[b.playerOID].sortNm) return 1;
if (Players[a.playerOID].sortNm < Players[b.playerOID].sortNm) return -1;
return 0;
});
// build an array of players for the time period
var s2 =new Array(), p, cnt, maxCnt =0, spd;
for (i =0; i <s.length;) {
p =s[i].playerOID;
cnt =0;
while (i <s.length && s[i].playerOID ==p) {
cnt++;
i++;
}
s2.push(new Array(p, cnt));
if (cnt >maxCnt) maxCnt =cnt;
}
var spd =
'<table cellpadding="2" cellspacing="0" width="100%">'
+'<tr>'
+'<td>period start:</td>'
+'<td colspan="2">' +theDT(new Date(t1), 'D dMy ' +TF[TFx][0]) +'</td>'
+'</tr>'
+'<tr>'
+'<td>period end:</td>'
+'<td colspan="2">' +theDT(new Date(t2), 'D dMy ' +TF[TFx][0]) +'</td>'
+'</tr>'
+'<tr>'
+'<td>screenshots:</td>'
+'<td><a href="javascript:showScreenshotsForPeriod(' +t1 +', ' +t2 +')">' +s.length +'</a></td>'
+'<td width="40%"> </td>'
+'</tr>';
if (s2.length >0) {
spd +=
'<tr style="background-color:#CCC;">'
+'<td colspan="3">Screenshots by Player</td>'
+'</tr>';
spd +='<div style="max-height:256px;">';
for (i =0; i <s2.length; i++) {
spd +=
'<tr>'
+'<td>'
+'<a href="javascript:showPlayerDetails(' +s2[i][0] +',\'\');">'
+theDisplayNm(Players[s2[i][0]].name)
+'</a>'
+'</td>'
+'<td align="right">'
+'<a href="javascript:showScreenshots(\'Screenshots from '
+theDisplayNm(Players[s2[i][0]].name)
+'\', \'Screenshots[i].playerOID=='
+s2[i][0] +'&&Screenshots[i].dtm>=' +t1 +'&&Screenshots[i].dtm<' +t2 +'\');">'
+s2[i][1]
+'</a>'
+'</td>'
+'<td>' +theLine(s2[i][1], maxCnt) +'</td>'
+'</tr>';
}
spd +='</div>';
}
document.getElementById('details').innerHTML =spd +'</table>';
}
//-----------------------------------
// More Globals
//-----------------------------------
function fix(n) {
// return integer n as a comma-delimited string
var f =n.toString();
var re = /(\d+)(\d{3})/;
while (re.test(f)) f = f.replace(re, '$1,$2');
return f;
}
function format(n, d) {
// return integer n as a string of at least d digits
var f =n.toString();
while (f.length <d) f ='0' +f;
return f;
}
function hide(i) {
// hide the object whose id is i
// document.getElementById(i).style.visibility ='hidden';
document.getElementById(i).style.display ='none';
}
function show(i) {
// hide the object whose id is i
// document.getElementById(i).style.visibility ='visible';
document.getElementById(i).style.display ='block';
}
function theDT (dt, f) {
// return text date and time for date object dt according to format f
// f: use d, D, m, M, Y, y, h, H, i, s, a, [any other character], respectively, to include day, abbreviated textual day of the week, numeric month with leading zero, abbreviated textual month, full year, 2-digit year, hours of 12-hour clock, hours of 24-hour clock, minutes, seconds, am/pm, and any other character, in given sequence (codes are consistent with PHP conventions)
var td ='', ampm ='';
var ff =f.split('');
for (var i =0; i <ff.length; i++) switch (ff[i]) {
case "d" : td +=dt.getDate().toString(); break;
case "D" : td +=DOTW[dt.getDay()]; break;
case "m" : td +=format(dt.getMonth() +1, 2); break;
case "M" : td +=MOTY[dt.getMonth()]; break;
case "Y" : td +=dt.getFullYear().toString(); break;
case "y" : td +=dt.getFullYear().toString().substr(2,2); break;
case "h" :
if (dt.getHours() >12) { td +=(dt.getHours() -12).toString(); break; }
if (dt.getHours() >0) { td +=dt.getHours().toString(); break; }
td +='12'; break;
case "H" : td +=dt.getHours().toString(); break;
case "i" : td +=format(dt.getMinutes(), 2); break;
case "s" : td +=format(dt.getSeconds(), 2); break;
case "a" : td +=(dt.getHours() >11) ? 'p.m.' : 'a.m.'; break;
default: td +=ff[i];
}
return td;
}
function theLine(c, t) {
// render an HTML table whose width is c's percentage of t
if (c <=0 || t <=0) return ' ';
return '<table cellpadding="0" cellspacing="0" bgcolor="#BBBBBB" width="' +Math.round(100 *c /t) +'%"><tr><td> </td></tr></table>';
}
// structure of a PB screen shot index line
// e.g.,<a href=pb000914.htm target=_blank>000914</a> "^3[MSG]Goose" (W) GUID=xxx...xxx(VALID) [2007.11.26 17:47:25]
// $1 ss file name
// $2 ss sequence #
// $3 player name
// $4 ?? e.g., W
// $5 GUID
// $6 ?? e.g., VALID
// $7 ss year
// $8 ss month
// $9 ss day
// $10 ss hour
// $11 ss minute
// $12 ss second
var ssRE = /.*?<a\s+href=.*?(pb\d+?\.htm).*?>(.*?)<\/a>\s*"([\s\S]*?)"\s+\((.*?)\).+GUID=([0-9a-f]+)\s*\((.*?)\)\s+\[(\d{4})\.(\d{2})\.(\d{2})\s+(\d{2})\d{2})\d{2})\]/i;
var ssPlayerRE = /.*?<a.*?>.*?<\/a>\s*"([\s\S]*?)"/i;
var ssX = /.*?<a\s+href=.*?(pb\d+?\.htm).*?>.*?<\/a>\s*([\s\S]*)/i;
</script>
</html>