Scrolling Tape Calculator
By William Bontrager
If you prefer to only have the calculator for your site instead of also learning how it works, you may get the code at http://willmaster.com/possibilities/demo/calculator.html
That page has a link for downloading a .zip file. When downloaded and uncompressed, you will have a file called readme.txt with instructions for use. It includes instructions for putting the Scrolling Tape Calculator into a popup window.
The current calculator does not operate from the keyboard because there is already a lot of information for this tutorial. A later tutorial may show how to capture keyboard clicks and execute functions depending on what was clicked -- including how to incorporate that into the Scrolling Tape Calculator
~~ Dynamic content for form textarea and text fields.
~~ Some text string formatting.
~~ Global variables to hold previous and cumulative values.
~~ Boolean variables.
~~ Image switching when it is clicked.
~~ Delayed execution of a function.
First, download the .zip file form the link at http://willmaster.com/possibilities/demo/calculator.html and uncompress the file. You will have a lot of image files and two HTML files, jscalc.html and jspopcalc.html.
jspopcalc.html is a demonstration of putting the Scrolling Tape Calculator inside a popup window. You may use it, if you want, but it is of no importance to this tutorial.
Now, we'll go over the HTML that creates the visible calculator:
~~ Notice that the form tag has a name. It's called "calculator".
~~ Notice that the textarea tag has a name. It's called "tape".
~~ Notice that the textarea tag has a cols="..." attribute. The number in the attribute is 17.
~~ Notice that the textarea tag has a rows="..." attribute. The number in the attribute is 7.
~~ Notice that the input tag has a name. It's called "nowtotal".
~~ Notice that the input tag has a size="..." attribute. The number in the attribute is 19.
The forms's textarea field is where the "scrolling tape" will be displayed. And the form's input text field is where the current key clicks on the number pad are displayed.
The first thing to do is initialize some variables that will be used throughout the program. Such variables are called "global" variables because they can be accessed anywhere within the program. (Variables that are created and used in functions get destroyed after the function is done. Those are called "local" variables.)
TapeWidth must be initialized with the number in the form textarea tag's cols="..." attribute.
Next, we initialize as many variables as there are rows in the form's textarea. (See the rows="..." attribute.) The variables are called line1, line2, etc. Each of those variables is initialized with a space and a line feed character -- except the last line, which only contains a space. This seeds the "scrolling tape" with blank lines.
Because some browsers won't create a scrollbar if later lines are longer than the textarea width, the while() statement lengthens the first line to force a scrollbar when the page is first loaded.
NowKeysWidth must be initialized with the number in the form input tag's size="..." attribute.
The NowTotal variable is initialized to zero. This global variable will hold the latest result of calculations. It will, at specific points in the program, be reset to zero.
The Current variable is set to a null string (a set of either single or double quotes with nothing between them). This global variable holds the current sequence of numbers clicked on the keypad.
The function keys on the keypad are "+", "-", "*", "/", "=", and "c". They add, subtract, multiply, divide, complete the calculation, and clear the current sequence of numbers that were clicked on the keypad, respectively. If the "c" is clicked a second time, in sequence, the global NowTotal is reset to zero and a line of hyphens appears on the scrolling tape.
The global variable PreviousF holds the most recent function key that was clicked. It is initialized with a space. At specific points in the program, is it reset with a space.
However, because the function key "c" does stuff only remotely related to the other function keys, the PreviousF variable does not change when "c" is clicked. For that, the
global variable PreviousC is used. PreviousC is used to indicate whether or not the previous key clicked was the "c" key. It is initialized to false.
PadFront() is used to lengthen text lines in the "scrolling tape" area so they align on the right. It is also used to lengthen text for the current number keys clicked area.
The next function is DisplayInNowWindow(), which accepts a string of characters, calls PadFront() to lengthen the text, and displays the result in the form's input text area.
Notice that DisplayInNowWindow() uses both the form's name and the input text field's name to tell the browser which value is changed.
The third function is AddLineToTape(), which accepts a string of characters and a single character. It formats the string to the proper length and appends the single character to the end. (The single character would be a symbol for one of the function keys on the keypad). AddLineToTape() moves all the other rows up one line and then puts the newly formatted string at the bottom.
Notice that AddLineToTape() uses both the form's name and the textarea's name to tell the browser which value is changed.
Now we come to the two functions that the keypad image links call, K() and F().
K() is called when a number or the decimal point is clicked. You'll see the link in the HTML code, with the value of the key click within the parenthesis so it is passed to the function.
K() accepts the value and appends it to the form's input text field. This lets the user always be aware of what their current number is.
The six function keys on the keypad call the function F(). You'll see it in the HTML code, calling the function with the value inside the parenthesis.
F() accepts the value and
~~ if it is a "c", it clears the form's input text field.
~~ if it is a sequential "c", it clears the current calculated total and prints a short line of hyphens on the "scrolling tape".
~~ if it is not a "c", it does the calculation as directed by the value.
F() has some subtle code:
The value F() is passed is assigned to the local variable s. But s is used in only a few places.
When F() encounters a sequential "c", the global PreviousF is reset to a space. This clears the instruction for when the next non-"c" function key is clicked. Otherwise, the next non-"c" function key click would do the calculations according to an old and possibly invalid instruction.
When a function key is clicked but there is no number in the form's input text field, F() will abandon the function. But before it abandons the function, it checks to see if local variable s is a "=". If so, and if the PreviousF variable is not a space, F() puts the current calculated
total with an "=" symbol on the end on the "scrolling tape". The tape doesn't scroll because the number displayed will not change (it is the same total as it was before); only the symbol on the right end of the line is different.
As you see, there are several instances when the global value PreviousF might be reset to a space. If so, the variable representing the current completed calculation, NowTotal, is set to zero.
If F() has not abandoned itself before this point, it adjusts NowTotal according to the instruction it received with the previous function key click. This may seem odd, but consider that it receives its calculation instruction before it receives the number it is to do the calculation on.
Example: 22 + 44 - 11
First, it gets the number 22, and puts it on the tape as the current calculated total (the first number in a calculation sequence is treated this way even though nothing has yet been calculated). Next, it gets the calculation instruction "+". Only after that does it get the number to do the calculation on: 44.
Then, the F() gets another calculation instruction, "-". After that, it gets the number to do the calculation on: 11
So F() has to remember what the previous instruction was in order to do the current calculation.
If there was no previous instruction or if PreviousF was reset to a space, F() simply copies the numerical value of the form's input text field as the current calculated total.
If PreviousF is not a space, F() puts the current value in the form's input field onto the tape with no function key symbol on the right hand side. If PreviousF is a space, then that means the number is the first of the sequence and would be repeated as the current calculated total is put on the tape.
F() then consults the local variable s. If it is the "=" symbol, NowTotal is zeroed and s resets itself to a space.
After this, the PreviousF variable is assigned the value of s.
The final act of F(), provided it got this far before it abandoned itself, is to set the global variable PreviousC to false.
The first global variable of this section is image_number_of_first_button
If the calculator's keypad images are the first (or only) images on the page, image_number_of_first_button must be initialized to 1 because the first button is the first
image on the page.
If you have other images on the page that appear in your HTML code before the calculator, then adjust the number accordingly. Note that if you get this number wrong it will be apparent when you use the calculator -- an image under the wrong key swap. In that case, just adjust the image_number_of_first_button initialization value until the
The next section determines whether or not the browser is capable of swapping images. This is necessary to know so that browser can be blocked from running the swapping
So we want only browsers capable of doing so to swap images.
The next section initializes a global variable with the number of calculator keypad buttons (you won't need to change that unless you change the number of keypad buttons) and makes room in memory for the files names of each up and down image on the keypad.
The next section fills those memory spots with the file names. Each up[#] and down[#] variable name contains the file name of the up and down position images. up contains the up image and down contains the down image. And so forth.
If you change the images for your keypad or move them to a different directory, you may need to also change the file names in this section. Example: up = "images/my_c.gif"
After that, room is made for them and then the images are loaded into memory.
The first three functions are called to make room in memory for the graphics file names, to make room for the graphics themselves, and to load the graphics into memory.
The last two functions swap the keypad images:
buttonup() swaps the "down" image back to the "up" image. It is called from buttondown().
When a keypad image is clicked, buttondown() swaps the "up" image for the "down" image, making it look like the key was pressed. You'll see the buttondown() function in each keypad image anchor tag of the HTML code, beginning with onClick=", which calls buttondown() when the image is clicked. Notice that the HTML code has a value between the parentheses of buttondown(). That value is a sequential number beginning with 1 and ending with 17, each number representing one image. buttondown() uses that value to determine which image to swap.
setTimeout() requires two items of information separated with a comma between the parenthesis: (1) an instruction and (2) how many milliseconds to wait before complying with the instruction.
buttondown() uses local variable f to create the instruction for setTimeout(). The instruction is the function buttonup() with the current button value in the parenthesis. Then buttondown() calls setTimeout() with variable f and the number 200. You may change the number 200 if you want the buttons to come back up quicker or remain down longer.
Happy Scrolling Tape Calculating!
William Bontrager, Programmer and Publisher
"Screaming Hot CGI" programs
"WillMaster Possibilities" ezine
Copyright 2000 by William and Mari Bontrager
| DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware. |
More Web Development Articles
More By Developer Shed