/** * abelard.org Configurable Practice Counter * * These functions provide the running for a highly configurable web browser-based counter. * This script may be reused on other websites on the following conditions: * * - All pages that display the counter must display a prominent and visible link to: * http://abelard.org/sums/teaching_number_arithmetic_mathematics_introduction.php * - With the following text: * "The Configurable Practice Counter was developed by the auroran sunset on behalf of abelard.org and is copyright to © 2009 abelard.org". * - Without modifications. * * * This version of the abelard.org Configurable Practice Counter provides the following features: * - Two modes: automatic and manual. * - Two directions: counting up and counting down. * - Configurable speed: from 0.1 seconds/change in 0.1 second increments. * - Configurable step size. * - Configurable base: from base 2 to base 32 inclusive. * - Configurable number of decimal places: from 0 to 5 inclusive. * - Support for negative numbers. * - Manual reset of counter value (including decimal places). * - Manual change of step size (including decimal places). * - A secondary resetable counter of the number of manual steps done, useful for multiplication and division sums. (v1.1) * * The counter is displayed in the HTML element with the ID "counterDiv". * Settings can be displayed in the following HTML elements: * - "autoSpan" values can be "Automatic (running)" or "Manual enabled" * - "directionSpan" values can be "Increasing" or "Decreasing" * - "speedSpan" value is the time between changes in seconds to one decimal place * - "stepSpan" value is the difference each count to the configured number of decimal places * - "baseSpan" value is the current numbering base used, between 2 and 32 * - "placesSpan" values is the number of decimal places to display, from 0 to 5 * - "manualSpan" value is the current count of manual steps done since the last reset (v1.1) * * HTML body onload command: "runCounter();updateSettingsDisplay()" * * Functions: * - runCounter : this is the function that updates the counter * - formatDecimalString : formats a string to be a decimal with the configured number of decimal places. * This is a workaround for a bug in JavaScript caused by the lack of proper type casting. * toFixed and toString(radix) don't work well together, so this is used to replace toFixed * in pure string format. * - changeSettings : can be called by buttons to change the various configuration parameters * - updateSettingsDisplay : updates all the settings HTML elements with the new values * - setCounterValue : resets the counter to the value found in the HTML element "newCounterValue" * - setStepValue : resets the counter step to the value found in the HTML element "newStepValue" * * $LastChangedBy : the auroran sunset$ * * $LastChangedDate : 27-Aug-2009$ * * @author the auroran sunset * @copyright 2009 abelard.org * @package PracticeCounter * @subpackage PracticeCounter * @version 1.1 */ var bDirectionIsUp = true; // is the counter going up or down? var iSpeed = 1000; // how often the counter updates in milliseconds, minimum = 100 var bAutoMode = false; //steps automatically, or only when the user clicks? var iStep = 1; // how much to add or subtract on each update var iBase = 10; // the base to display in, allowed values from 2->36 var iCounterValue = 0; // the value of the counter var iPlaces = 0; // how many decimal places to display, allowed values from 0 to 5. var iChangeSpeed = 100; // amount to increase/decrease the speed when changing var iChangeStep = 1; // amount to increase/decrease the step size when changing var iChangeBase = 1; // amount to increase/decrease the base when changing var iChangePlaces = 1; // amount to increase/decrease the number of decimal places displayed var iManualCounter = 0; // number of manual steps done since the last reset function runCounter( bManual ) { // don't allow manual steps when in auto mode if ( !bManual || !bAutoMode ) { iCounterValue = parseFloat(iCounterValue); if ( bDirectionIsUp ) { iCounterValue += iStep; } else { iCounterValue -= iStep; } var sCounterValue = iCounterValue; sCounterValue = parseFloat(sCounterValue); sCounterValue = sCounterValue.toString(iBase); sCounterValue = formatDecimalString(sCounterValue); document.getElementById('counterDiv').innerHTML = sCounterValue; if ( bAutoMode ) { setTimeout('runCounter()', iSpeed); } else if ( bManual ) { // this was a manual step iManualCounter++; updateSettingsDisplay(); } } } function formatDecimalString ( sInputString ) { // takes a string (with or without decimal places) and formats as a decimal string with iPlaces after the point var sOutputString = ""; var aDecimalSplit = new Array(); if ( sInputString.indexOf('.') != -1 ) { aDecimalSplit = sInputString.split('.'); } else { aDecimalSplit[0] = sInputString; aDecimalSplit[1] = ""; } sOutputString += aDecimalSplit[0]; if ( iPlaces == 0 ) { return sOutputString; } sOutputString += "."; var iPlacesStart = aDecimalSplit[1].length; if ( iPlacesStart > iPlaces ) { aDecimalSplit[1] = aDecimalSplit[1].substr(0,iPlaces); } else if ( iPlacesStart < iPlaces ) { for (i=1;i<=(iPlaces-iPlacesStart);i++) { aDecimalSplit[1] += "0"; } } sOutputString += aDecimalSplit[1]; return sOutputString; } function changeSettings ( sSetting, bIncrease ) { // These settings can be changed: // "Mode" -> count continues automatically, or only when user clicks - the second parameter is ignored // "Direction" -> counting up or counting down - the second parameter is ignored // "Speed" -> how fast are we counting? // "Step" -> how much do we add or remove each time? // "Base" -> the base to display the number in? // "Places" -> the number of decimal places to display? // "ResetManual" -> resets the counter of the number of manual step - the second parameter is ignored // All except "Mode", "Direction" & "ResetManual" can be increase or decreased depending on the second parameter. switch ( sSetting ) { case "Mode": bAutoMode = !(bAutoMode); runCounter(); break; case "Direction": bDirectionIsUp = !(bDirectionIsUp); break; case "Speed": // increase speed = LOWER number (ie lower pause between changes) iSpeed = ( bIncrease ) ? ( iSpeed - iChangeSpeed ) : ( iSpeed + iChangeSpeed ); // don't allow speeds faster than changing every 100 milliseconds if ( iSpeed < 100 ) { iSpeed = 100; } break; case "Step": // sometimes JavaScript gets confused after entering a number - turn it back to a number just in case iStep = parseFloat(iStep); iStep = ( bIncrease ) ? ( iStep + iChangeStep ) : ( iStep - iChangeStep ); break; case "Base": // base must stay between 2 and 32 inclusive. if ( bIncrease && iBase < 32 ) { iBase += iChangeBase; } else if ( !bIncrease && iBase > 2 ) { iBase -= iChangeBase; } else { // something's wrong, but just ignore it - can't be bothered to raise an error. ;-) } break; case "Places": // number of decimal places must stay between 0 and 5 inclusive. if ( bIncrease && iPlaces < 5 ) { iPlaces += iChangePlaces; } else if ( !bIncrease && iPlaces > 0 ) { iPlaces -= iChangePlaces; } else { // something's wrong, but just ignore it - can't be bothered to raise an error. ;-) } break; case "ResetManual": iManualCounter = 0; break; default: // something's wrong, but just ignore it - can't be bothered to raise an error. ;-) } updateSettingsDisplay(); } function updateSettingsDisplay() { var sSettingsValue = (bAutoMode) ? "Automatic (running)" : "Manual enabled"; document.getElementById('autoSpan').innerHTML = sSettingsValue; sSettingsValue = (bDirectionIsUp) ? "Increasing" : "Decreasing"; document.getElementById('directionSpan').innerHTML = sSettingsValue; sSettingsValue = ( (iSpeed / 1000).toFixed(1) ).toString(); document.getElementById('speedSpan').innerHTML = sSettingsValue; sSettingsValue = ( iStep.toFixed(iPlaces) ).toString(); document.getElementById('stepSpan').innerHTML = sSettingsValue; sSettingsValue = iBase.toString(); document.getElementById('baseSpan').innerHTML = sSettingsValue; sSettingsValue = iPlaces.toString(); document.getElementById('placesSpan').innerHTML = sSettingsValue; sSettingsValue = iManualCounter.toString(); document.getElementById('manualSpan').innerHTML = sSettingsValue; } function setCounterValue() { var newValue = document.getElementById('newCounterValue').value; newValue = parseFloat(newValue); iCounterValue = newValue.toFixed(iPlaces); var sTemp = iCounterValue; sTemp = parseFloat(sTemp); sTemp = sTemp.toString(iBase); sTemp = formatDecimalString(sTemp); document.getElementById('counterDiv').innerHTML = sTemp; } function setStepValue() { var newValue = document.getElementById('newStepValue').value; newValue = parseFloat(newValue); iStep = newValue.toFixed(iPlaces); iStep = parseFloat(iStep); updateSettingsDisplay(); }