The Personal Status Board (PSB) Demo Code
Mostly, the codes to display tables and data were done with document.write statements, which are especially handy when mixing JavaScript (or PHP or MySQL) data arrays and HTML tables. Note how we are sticking id values into a couple of the <td> tags, to be of great use later when we use JavaScript's innerHTML feature to update the table data (that you enter) as you watch:
var number_records_in_table = 12;
document.write("<div id='s' style='border:1px solid black;position:absolute;top:53px;left:2px;background-color:#eee;'>");
document.write("<table border='1' width='578'>");
document.write("<tr><th width='116'>Name</th><th width='25'>ID</th><th width='25'>Status</th><th width='412'>Comment</th></tr>");
for (i=0;i<number_records_in_table;i++){
document.write("<tr><td>" +fname[i]+ "</td><td>" +IDs[i]+ "</td><td id='st"+i+"'>" +memstatus[i]+ "</td> <td id='com"+i+"'>" +comments[i]+ "</td></tr>")};
document.write ("</table>");
document.write ("</div>");
Below we use my browser sniffers to adjust some display-related values according to which browser is being used, but IE5 for Mac is an obsolete, buggy mess, and is unlikely to work right with the PSB demo or the PSB either, so if you have it, dump it and use Safari:
mactest=(navigator.userAgent.indexOf("Mac")!=-1) //My browser sniffers
is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1
Netscape=(navigator.appName.indexOf("Netscape") != -1)
msafari=(navigator.userAgent.indexOf("Safari")!= -1)
wsafari=0; if(!mactest&&msafari){wsafari=1;msafari=0}
is_opera = 0; if(window.opera){is_opera=1}
is_ie_mac = 0; is_ie=0;if(document.all){is_ie=1}
if(is_ie&&mactest){is_ie_mac=1}
a='82px';b='25px';h='25px';n=572;if(is_ie_mac){a='82px';b='23px';h='23px';n=570;}
if(Netscape&&!mactest){a='83px';b='26px';h='25px';};
if(Netscape&&mactest){a='84px';b='25px';h='25.7px';n=585;};
if(msafari){a='80px';b='24px';h='24px';n=570;};
if(wsafari&&!is_chrome){n=583;};
if(is_chrome){n=583;};
if(is_opera){n=565;};
z=410;zz=360;zzz=340;zzzz=391;if (number_records_in_table>10){z=410+((number_records_in_table - 10)*30);zz=z-50;zzz=z-73;};if(Netscape||is_opera){zzzz=402}
Below we use a FOR loop to print .js data into a table. The cool detail here is
psb[parseInt(memstatus[i],10)], which gets the correct psb status code meaning (out of 100 possibles) for each of the 12 members, and where meanings are based on the current status code of each of the members, and where i is member id (1 to 12) and memstatus[i] is the current status per member.
document.write("<div id='q' style='border:1px solid black;background-color:#eee;position:absolute;top:53px;left:582px'><table width=\"418\" border=\"1\" cellpadding=\"1\">");
document.write("<tr><th width='50' height='+h+'>Change</th><th width='373'>Meanings</th></tr>");
for (i=0;i<number_records_in_table;i++){document.write( "<tr><td>" + " " + "</td><td id='mn"+i+"'>" + psb[parseInt(memstatus[i],10)] + "</td></tr>");}
document.write ("</table></div>");
Below we warn commenters that they need to stop at the end of the data input box. This is necessary when you wish to avoid the ugliness of a Courier font. Since Courier is a monospaced font, which means that all characters have the same width, you can use the width of any of its characters to determine how wide the input box should be. If we used Courier, you could type 44 numbers—12345678901234567890123456789012345678901234—and you'll always get 44 characters in the box—including capital W characters. W is much wider in other fonts, which means that the input box will hold less than half as many characters if you type lots of Ws. We use Times New Roman for td and input tags since it is easy to read. This gives us a good looking display that is easy to read and the input box for comments will get the Times New Roman font too. We've allowed a maximum of 44 characters, which is great for most comments, but if people use capitals and Ws, the box won't hold nearly 44 characters. If we allow them to go past the box end and keep typing, it'll stop them at 44, but once the table updates, the result will be a table that widens out and wrecks the display as one table overlaps another. So we put up a note to avoid this. They may choose to violate this and wreck the looks of the table, but why? PSBs are for the members' benefit, not ours. There is no such thing in JavaScript as a way to check where a character (being typed) is on the screen and make them stop at the end, even though in the C language it may be doable. So the choices were the ugly Courier font (boo!), limiting users to 20 characters (boo!), or using a warning notice (yea!).
document.write ("<div style='position:absolute;top:"+zzz+"px;left:"+n+"px'><i>Please cease typing when you get here</i><span class='arrow'><b>↓</b></span></div>");
Below we create a form on the fly. Note that its top positioning is zz, a calculated value depending on how many members there are. A few members would require that the form display higher on the screen, while more members puts it lower. The form action is blank because we're not submitting it or leaving the page—we're running a function with an onClick event instead of submitting.
document.write ("<form style='position:absolute;top:"+zz+"px;left:10px;width:989px;' id='status' name='PSBform' method='get' action=' '><b id='newstatus'>Member </b><label for='status'><b>Status: </b><input type='text' name='status' size='2' maxlength='2' value=''></label><label for='comment' style='position:absolute;top:0px;left:370px;width:629px;'><b>Comment (optional): </b><input type='text' name='comment' size='44' maxlength='44' id='c' value=''></label><input type='button' value='Update PSB' onclick='return validate()' class='f'><input type='reset' value='Reset' class='g'></form>");
Below we use a loop to print out all the status codes and their meanings, complete with subtitles. Since all codes must have 2 digits, we converted the loop's i variable to u with a string type, then added a "0" character if the i value was 0 through 9. The 2-digit i values needed no processing. If the second character is "0", a subtitle is printed, since every 10 codes the status codes are in a different generic category.
document.write("<div id='r' style='background-color:#eee;position:absolute;top:"+z+"px;left:"+zzzz+"px'><table border=\"1\" cellpadding=\"1\">");
document.write("<tr><th>Status Code</th><th>Meaning</th></tr>");
f=0;u=" ";
for (i=0;i<100;i++){
u=i.toString();if (u.length<2){u="0"+u}
if(u.charAt(1)=="0"){
document.write( "<tr><th colspan=2>" + sub_title[f] + "</th></tr>");f=f+1}
document.write( "<tr><td>" + u + "</td><td>" + psb[i] + "</td></tr>")}
document.write ("</table><br><br><br></div><br><br><br>");
Below we put a column of buttons next to the Comment and Meaning columns, so users can choose whose status and comment to update. We coded it twice, with Mac computers getting one image and Windows computers getting another. This is because the Mac default table displaying procedures make skinnier rows. Note that an OnClick event not only sends the focus to the status input box, it also sets the value of the member variable and runs a function newstatus(), which sets the comment box value to nothing (so old comments do not linger in case you updated another member first), sets the status input box to its current value, and replaces the word "Member" with the actual name of the member.
document.write("<div id='g' style='position:absolute;top:"+a+";left:587px'><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">");
if(!mactest){for (i=0;i<number_records_in_table;i++){document.write( "<tr><td style='height:"+h+";'><a HREF='#' onclick='member="+i+",newstatus(),document.PSBform.status.focus()'><div style='height:"+b+";'><IMG SRC='change.png' WIDTH=40 HEIGHT=22 BORDER=0></a></div></td></tr>");}
}else{
for (i=0;i<number_records_in_table;i++){document.write( "<tr><td style='height:"+h+";'><a HREF='#' onclick='member="+i+",newstatus(),document.PSBform.status.focus()'><div style='height:"+b+";'><IMG SRC='change-.png' WIDTH=40 HEIGHT=18 BORDER=0></a></div></td></tr>");}}
document.write ("</table></div>");
In the first function below, we set the comment box value to nothing (so old comments do not linger in case you updated another member first), set the status input box to its current value for the selected member, and replace the word "Member" with the actual name of the member.
In the second function, we make sure they've clicked an image to choose a member (by seeing if the member variable contains a valid number, which values less than zero are not. We alert them to choose first if they didn't. We next use the Javascript Date() function to define some date and time variables, which we then put together in such a way that the variable ttt contains month, day, and time.
We check that their input contains 2 digits and if not, we alert them. We update the chosen member's status array value. Then we append their member number after the string 'st' to use to find their <td> tag so we can use it to update the data (in their td tag in the table) with the innerHTML function in JavaScript. We get the typed comment value from the input box and use regular expressions to clean it up. We replace the ' characters with ; characters. Even though it may look weird, we wanted to prevent any MySQL injection operations from hackers. We'd have just dumped these apostrophes except we didn't want users to see dont, wont, shouldnt, Ill, Id, thats, whats, didnt, and other such words and think they were spelling morons. We could have escaped the bad characters (\') but just didn't want those dangerous entities in our db, and, besides, the backslash would have added an extra character, and what if they really used all 44 alloted characters as well as lots of apostrophes? We played it safe.
Another very dangerous entity is 2 hyphens in a row. This got replaced twice with one space character and one hyphen. Why twice? Because an odd number of hyphens could still let "--" leak through. The other very dangerous entity is the = sign. This got dumped, using regular expressions, along with most other special characters ([@#$%^&*()+|\={}[]:"'/><) and replaced with a space, so no hacker will do a number on the site or the db. The cleaned-up comment was put into the member's comment array value with date and time appended to it, then put into the displayed PSB table. Then we append their member number after the string 'comm' to use to find their <td> tag so we can use it to update the table, with the innerHTML function in JavaScript. You may recall these id values getting stuck into these tags, earlier, as the display table was being created. Then we append their member number after the string 'mn' to use to find their <td> tag so we can use it to update their row's status code Meaning value in the table, with the innerHTML function in JavaScript. Finally, we null the status and comment values in the form so they are empty and change the member variable to -1 (which acts as a "no-selection-yet" flag) and change the member's name back to the word Member, next to the input box.
function newstatus(){
document.PSBform.status.value=memstatus[member];
document.PSBform.comment.value="";
document.getElementById('newstatus').innerHTML =
fname[member]+" ";}
function validate(){
if(member<0){alert("Please click a 'Change Status' button first.");return false}
var currentTime = new Date();
var currentDate = new Date();
var day = currentDate.getDate();
var month = currentDate.getMonth()+1;
var hours = currentTime.getHours();
var minutes = currentTime.getMinutes();
var suffix = "am";var ttt="";
if (hours >= 12) {suffix = "pm";hours = hours - 12;}
if (hours == 0) {hours = 12;}
if (minutes < 10){minutes = "0" + minutes;}
ttt=month + "/" + day + " " + hours + ":" + minutes + suffix;
d=document.PSBform;
Status=d.status.value;
if (Status.length!=2 || isNaN(Status)) {alert("Please input any two digits for the personal status code.");return false}
memstatus[member]=Status;
sta='st'+member;sta=sta.toString();
document.getElementById(sta).innerHTML = memstatus[member];
Comment=d.comment.value;
Comment=Comment.replace(/--/g," -");
Comment=Comment.replace(/--/g," -");
Comment=Comment.replace(/[@#$%\^&\*\(\)\+\|\\=\{\}\[\]:\/><]/g," ");
Comment=Comment.replace(/'/g,"\'");
Comment=Comment.replace(/"/g,"\"");
d.comment.value=Comment;
comments[member]=Comment+
"<span style='font-size:11px;'> "+ttt+"</span>";
comm='com'+member;comm=comm.toString();
document.getElementById(comm).innerHTML = comments[member];
mean='mn'+member;mean=mean.toString();
document.getElementById(mean).innerHTML = psb[parseInt(memstatus[member],10)];
document.getElementById('newstatus').innerHTML = "Member ";
document.PSBform.comment.value="";
document.PSBform.status.value="";
member=-1;
return true;}