Introduction
This is a somewhat advanced JavaScript Typing Test system that will allow you to place a table and a few blocks of code on your website (perhaps on a job application system as we did) and get a detailed statistical information on your user's typing ability, including:
- Words Per Minute (WPM)
- Accuracy Percentage Rating
- Total Words Typed
- Good Words / Bad Words Typed (Errors)
- Time Taken to Complete
- More as needed
To see the system in use, visit http://www.itsllc.us/TypingTest_1.asp; you may also download a lower quality version above, or follow along with the code below.
Background
There isn't much of a background to this code except for the fact that it uses JavaScript as a base to execute -- and yes, this is completely client side scripted. You could do the same thing in a server side scripting language or environment such as ASP; however, it would more than likely be less effective.
Using the code
To implement the code below, simply write (or copy and paste -- which is quicker, yeah) the code below into the <HEAD>
section of your document -- or anywhere else as you wish, if you are using an include.
Shown below is the JavaScript code required to make the system work. It's fairly straightforward, and very high on the "commented" side -- so you shouldn't have any issues understanding; but if you do, don't hesitate to leave a comment or contact me.
<SCRIPT LANGUAGE="JavaScript">
var hasStarted = false;
var intToTestCnt = 4;
var strToTest = new Array("Innovative Technical Solutions, LLC (ITS) is a Native" +
" American owned business that was established in Paducah, " +
"Kentucky in April 2000. ITS is a certified and Small Disadvantaged " +
"Business by the U.S. Small Business Administration. Our headquarters " +
"are in Paducah, Kentucky and we have" +
" satellite offices located in Tennessee, " +
"Ohio, and Illinois. ITS is a leading" +
" edge Information Technology firm that " +
"is comprised of professionals with a broad" +
" range of experience in software " +
"development, high-speed imaging/scanning (TIFF, PDF, Text, " +
"and OCR capabilities), document management, records management," +
" relevance management, information security, environmental " +
"management, fire services management, fire protection " +
"engineering, and protective force expertise.",
"The ITS Information Technology (IT) Team are experts " +
"in the identification, capture, indexing, microfilming, imaging, " +
"disposition, turnover, storage, and retrieval of records, " +
"and in the administration of records management databases. " +
"The types of records we have extensive experience in managing " +
"include waste management, hazardous waste, waste shipment, " +
"environmental compliance, environmental" +
" monitoring, feasibility studies, " +
"environmental work plans, cleanup actions, cemetery records, and " +
"various Federal laws such as CERCLA, Paper Reduction, " +
"Pollution Prevention, and Clean Water and Air.",
"Collectively, the professional background of key ITS personnel " +
"demonstrates Fortune 100 Company experience that includes, " +
"but is not limited to, DOE, the Department of Defense, EPA, the " +
"Tennessee Valley Authority (TVA), Lockheed Martin Utility Services, " +
"Lockheed Martin Energy Systems, British Nuclear Fuels Limited, various " +
"state and local agencies, and USEC." +
" We consider the depth and magnitude " +
"of this experience as a proposition value " +
"to both our current and future customers.",
"With our years of experience, we completely understand document " +
"management and technology. We know the importance of deadlines and " +
"we know the importance of production without error. We refuse to " +
"over-commit to deadlines that can not be met. Dedication to excellence " +
"in providing quality products and services through innovative ideas and " +
"processes. Steadfast resolve to a positive working environment that " +
"allows for the personal and professional development of all employees, " +
"while sustaining project service, and customer satisfaction. " +
"Commitment to the highest ethical management practices that " +
"recognize client satisfaction as a top priority.")
var strToTestType = "";
var checkStatusInt;
function Left(str, n){
if (n <= 0)
return "";
else if (n > String(str).length)
return str;
else
return String(str).substring(0,n);
}
function Right(str, n){
if (n <= 0)
return "";
else if (n > String(str).length)
return str;
else {
var iLen = String(str).length;
return String(str).substring(iLen, iLen - n);
}
}
function beginTest()
{
hasStarted = true;
day = new Date();
cnt = strToTestType.split(" ").length;
word = cnt;
startType = day.getTime();
document.getElementById("printB").disabled = true;
calcStat();
document.JobOp.start.value = "-- Typing Test Started --";
document.JobOp.start.disabled = true;
document.JobOp.given.value = strToTestType;
document.JobOp.typed.value = "";
document.JobOp.typed.focus();
document.JobOp.typed.select();
}
function deterCPProtect()
{
document.JobOp.typed.focus();
}
function endTest()
{
clearTimeout(checkStatusInt);
eDay = new Date();
endType = eDay.getTime();
totalTime = ((endType - startType) / 1000)
wpmType = Math.round(((document.JobOp.typed.value.replace(/ /g,
" ").split(" ").length)/totalTime) * 60)
document.JobOp.start.value = ">> Re-Start Typing Test <<";
document.JobOp.start.disabled = false;
document.JobOp.stop.style.display="none";
document.JobOp.start.style.display="block";
var typedValues = document.JobOp.typed.value.replace(/ /g, " ");
var neededValues = Left(document.JobOp.given.value,
typedValues.length).replace(/ /g, " ").split(" ");
typedValues = typedValues.split(" ");
document.JobOp.typed.disabled=true;
var tErr = document.getElementById("stat_errors");
var tscore = document.getElementById("stat_score");
var tStat = document.getElementById("stat_wpm");
var tTT = document.getElementById("stat_timeleft");
var tArea = document.getElementById("TypeArea");
var aArea = document.getElementById("AfterAction");
var eArea = document.getElementById("expectedArea");
var goodWords = 0;
var badWords = 0;
var errWords = "";
var aftReport = "<b>Detailed Summary:</b><br>" +
"<font color=\"DarkGreen\">";
document.getElementById("printB").disabled = false;
var str;
var i = 0;
for (var i = 0; i < word; i++)
{
if (typedValues.length > i)
{
var neededWord = neededValues[i];
var typedWord = typedValues[i];
if (typedWord != neededWord)
{
badWords = badWords + 1;
errWords += typedWord + " = " + neededWord + "\n";
aftReport += "<font color=\"Red\"><u>" +
neededWord + "</u></font> ";
}
else
{
goodWords = goodWords + 1;
aftReport += neededWord + " ";
}
}
else
{
}
}
aftReport += "</font>";
aftReport = "<b>Typing Summary:</b><br>You typed " +
(document.JobOp.typed.value.replace(/ /g, " ").split(" ").length) +
" words in " + totalTime + " seconds, a speed of about " +
wpmType + " words per minute.\n\nYou also had " + badWords +
" errors, and " + goodWords + " correct words, giving scoring of " +
((goodWords / (goodWords+badWords)) * 100).toFixed(2) +
"%.<br><br>" + aftReport;
tErr.innerText = badWords + " Errors";
tStat.innerText= (wpmType-badWords) + " WPM / " + wpmType + " WPM";
tTT.innerText = totalTime.toFixed(2) + " sec. elapsed";
tscore.innerText = ((goodWords / (goodWords+badWords)) * 100).toFixed(2) + "%";
aArea.style.display = "block";
tArea.style.display = "none";
eArea.style.display = "none";
aArea.innerHTML = aftReport.replace(/undefined/g, " ");
}
function calcStat()
{
try {
checkStatusInt=setTimeout('calcStat();',250);
var tStat = document.getElementById("stat_wpm");
var tTT = document.getElementById("stat_timeleft");
var tProg = document.getElementById("stProg");
var tProgt = document.getElementById("thisProg");
var tArea = document.getElementById("TypeArea");
var aArea = document.getElementById("AfterAction");
var eArea = document.getElementById("expectedArea");
var thisTyped = document.JobOp.typed.value.replace(/ /g, " ");
eDay = new Date();
endType = eDay.getTime();
totalTime = ((endType - startType) / 1000)
wpmType = Math.round(((thisTyped.split(" ").length)/totalTime) * 60)
tStat.innerText=wpmType + " WPM";
document.JobOp.stop.disabled = false;
document.JobOp.stop.style.display="block";
document.JobOp.start.style.display="none";
if (Number(60-totalTime) < 5)
{
tTT.innerHTML="<font color=\"Red\">" + String(totalTime.toFixed(2)) +
" sec. / " + String(Number(60-totalTime).toFixed(2)) +
" sec.</font>";
}
else
{
if (Number(60-totalTime) < 15)
{
tTT.innerHTML="<font color=\"Orange\">" +
String(totalTime.toFixed(2)) + " sec. / " +
String(Number(60-totalTime).toFixed(2)) + " sec.</font>";
}
else
{
tTT.innerHTML=String(totalTime.toFixed(2)) + " sec. / " +
String(Number(60-totalTime).toFixed(2)) + " sec.";
}
}
if ((((thisTyped.split(" ").length)/word)*100).toFixed(2) >= 100)
{
tProg.width="100%";
tProgt.innerText = "100%";
}
else
{
tProg.width=String((((thisTyped.split(" ").length)/word)*100).toFixed(2))+"%";
tProgt.innerText = tProg.width;
}
if (thisTyped.value == document.JobOp.given.value)
{
endTest();
}
if (word <= (thisTyped.split(" ").length))
{
endTest();
}
if (totalTime >= 60)
{
endTest();
}
} catch(e){};
}
function doCheck()
{
if (hasStarted == false)
{
beginTest();
}
}
</SCRIPT>
When you have the JavaScript inserted into the page, all you need then is the code for the components (which was done fairly quickly without the use of CSS -- as it is a little messy, you get the point and can re-write or organize as you wish).
<div align="center">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td style="border-bottom: 2px solid #354562; padding: 4px" class="titlec">
<input disabled="" id="printB" onclick="window.print();"
type="button" value="Print Results" name="printB"
style="float: right; font-size: 8pt; font-family: Arial" />
<input onclick="document.getElementById('AfterAction').style.display='none';
document.getElementById('expectedArea').style.display='block';
document.getElementById('typeArea').style.display='block';
document.JobOp.typed.value='';document.JobOp.typed.disabled=false;
randNum = Math.floor((Math.random() * 10)) % intToTestCnt;
strToTestType = strToTest[randNum];
document.JobOp.given.value = strToTestType;"
type="button" value="New Test"
name="newtest"
style="float: right; font-size: 8pt; font-family: Arial" />ITS
Typing Test System</td>
</tr>
</tbody>
</table>
</div>
<table border="0" cellpadding="0"
cellspacing="0" width="100%">
<tbody>
<tr>
<td style="border-bottom: 1px dotted #860E36; padding: 4px"
class="titlea" background="Images/Lt_Red_Back.gif" width="460">
Accurately and precisely evaluate your typing speed and accuracy.</td>
<td style="border-bottom: 1px dotted #860E36; padding: 4px"
class="titlea" background="Images/Lt_Red_Back.gif" width="190">
<p align="right">v1.0</p>
</td>
</tr>
<tr>
<td style="padding: 4px" class="bodya" colspan="2">
<form name="JobOp">
<table border="0" cellpadding="5" width="100%">
<tbody>
<tr>
<td>
<table border="0" cellpadding="5" width="100%">
<tbody>
<tr>
<td align="center"
style="border-left: 1px solid #344270; border-right: 2px solid #344270;
border-top: 1px solid #344270; border-bottom: 2px solid #344270;
padding: 5px; background-color: #CED3E8"
background="Images/Blue_Back.gif">
<b><font face="Arial" size="2" color="#FFFFFF">Net /
Gross WPM</font></b></td>
<td align="center"
style="border-left: 1px solid #344270;
border-right: 2px solid #344270; border-top: 1px solid #344270;
border-bottom: 2px solid #344270; padding: 5px;
background-color: #CED3E8"
background="Images/Blue_Back.gif">
<b><font face="Arial" size="2" color="#FFFFFF">Entry
Errors</font></b></td>
<td align="center"
style="border-left: 1px solid #344270; border-right: 2px solid #344270;
border-top: 1px solid #344270; border-bottom: 2px solid #344270;
padding: 5px; background-color: #CED3E8"
background="Images/Blue_Back.gif">
<b><font face="Arial" size="2" color="#FFFFFF">Accuracy</font></b></td>
<td align="center"
style="border-left: 1px solid #344270; border-right: 2px solid #344270;
border-top: 1px solid #344270; border-bottom: 2px solid #344270;
padding: 5px; background-color: #CED3E8"
background="Images/Blue_Back.gif">
<b><font face="Arial" size="2" color="#FFFFFF">Elapsed
/ Remaining</font></b></td>
</tr>
<tr>
<td align="center"><font size="2" face="Arial">
<div id="stat_wpm">
Not Started</div>
</font></td>
<td style="border-left: 1px dotted #8794C7; border-right: 1px dotted #8794C7;
border-top-width: 1px; border-bottom-width: 1px" align="center">
<font size="2" face="Arial">
<div id="stat_errors">
Waiting...</div>
</font></td>
<td style="border-left-width: 1px; border-right: 1px dotted #8794C7;
border-top-width: 1px; border-bottom-width: 1px" align="center">
<font size="2" face="Arial">
<div id="stat_score">
Waiting...</div>
</font></td>
<td align="center"><font size="2" face="Arial">
<div id="stat_timeleft">
0:00</div>
</font></td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td style="border-left-width: 1px; border-right-width: 1px;
border-top: 1px solid #344270; border-bottom-width: 1px">
<div id="expectedArea" style="display:block">
<p style="margin-top: 0; margin-bottom: 0">
<font color="#7A88C0" face="Arial" size="1">
<textarea name="given" cols="53" rows="10"
wrap="on" onfocus="deterCPProtect();"
style="width: 100%; border: 1px solid #344270; padding: 2px;
font-family:Arial; font-size:9pt">
Click on the button below to start the typing test.
What you will be expected to type will appear here.
</textarea></font>
</p>
</div>
</td>
</tr>
<tr>
<td>
<p align="center" style="margin-top: 0; margin-bottom: 2px">
<input type="button"
value=">> Start Typing Test <<" name="start"
onclick="beginTest()"
style="display:block; border-left:1px solid #293358; border-right:2px
solid #293358; border-top:1px solid #293358; border-bottom:2px solid #293358;
width: 100%; background-color: #9BB892; color:#FFFFFF;
background-image:url('Images/Green_Back.gif')" /></p>
<p align="center" style="margin-top: 0; margin-bottom: 0">
<input disabled="" type="button"
value=">> End Typing Test <<"
name="stop" onclick="endTest()"
style="display:none; border-left:1px solid #293358; border-right:2px
solid #293358; border-top:1px solid #293358; border-bottom:2px
solid #293358; width: 100%; background-color: #F05959;
color:#FFFFFF; background-image:url('Images/Red_Back.gif')" /></p>
</td>
</tr>
<tr>
<td style="font-family: Arial; font-size: 9pt">
<div id="typeArea" style="display:block">
<table border="0" width="100%" cellspacing="1">
<tbody>
<tr>
<td style="border: 1px solid #9CA8D1; background-color: #EAECF4">
<div align="left">
<table id="stProg" border="0"
width="0%" cellspacing="1">
<tbody>
<tr>
<td style="border: 1px solid #344270; background-color: #8F9BCB;
font-family:Arial; font-size:8pt; color:#FFFFFF"
align="right" background="Images/Blue_Back.gif">
<div id="thisProg">
0%</div>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
<p style="margin-top: 0; margin-bottom: 0">
<font color="#7A88C0" face="Arial" size="1">
<textarea onkeypress="doCheck();" onkeydown="//calcStat()"
name="typed" cols="53" rows="10" wrap="on"
style="width: 100%; border: 1px solid #344270; padding: 2px; font-family:Arial;
font-size:9pt"></textarea></font>
</p>
</div>
<div id="afterAction" style="display:none">
</div>
</td>
</tr>
<script>
randNum = Math.floor((Math.random() * 10)) % intToTestCnt;
strToTestType = strToTest[randNum];
document.JobOp.given.value = strToTestType;
document.JobOp.typed.focus();
</script>
</tbody>
</table>
</form>
</td>
</tr>
</tbody>
</table>
History
- 03/16/2009 - Initial release.
- 03/17/2009 - Modified system for accuracy; added timer; and, added a detailed after-action report.