Tuesday, July 16, 2013
The Credit to My Credit Card
Blog Entry #295
We return now to the "So, You Want A Shopping Cart, Huh?" order.html page and the submission of its order form. Unlike Joe's order form, the order form at Gordon's original order.htm page provides a credit card facility, namely, the page's Choose Order Method table offers an On-line / Credit Card: option and is followed by a Credit Card Info table with fields for inputting a credit card number and expiration date.
As you would expect, the order.htm page's form submission code is quite a bit different than that for the order.html page, and I thought it would be interesting to look at the former in today's post.
The orderSubmit( ) function
As at the order.html page, clicking the button at the bottom of the order.htm page calls an order.htm orderSubmit( ) function
function orderSubmit(type) {
if (type == "order") { ... }
else {
if (!(checkGiftLength( ))) {
document.order.form_action.value = type;
document.order.submit( );
return true; }
else return false; } }
and passes it an order string argument. The
if (type == "order") { ... }
gate is accompanied by an else clause that, if type and order were not equal, would call a checkGiftLength( ) function whose (convertible-to-)false return would cause the form to submit. However, there is no checkGiftLength( ) function in the order.htm source.Here's what we've got if type and order are equal (and they are):
if (type == "order") {
if ( ! ((document.order.order_type[0].checked && checkCardNumber( )) || checkRequired( ) || checkExpireDate( ))) {
document.order.form_action.value = type;
document.order.submit( );
return true; }
else return false; }
Three subconditions must evaluate to false in order to submit the order form:
(1)
(document.order.order_type[0].checked && checkCardNumber( ))
(2)
checkRequired( )
(3)
checkExpireDate( )
I've got your number
The common name of the radio buttons in the order.htm Choose Order Method table is order_type. Strangely, the On-line / Credit Card: radio button has a checked attribute set to an empty string (the other two radio buttons don't have a checked attribute):
<font size="2">On-line / Credit Card: <input type="radio" checked="" name="order_type" value="credit"></font>
The
checked=""
setting is syntactically incorrect and I'm not quite sure what Gordon meant for it to do - on my computer, it checks the radio button with Communicator 4.61 but has no effect (the radio button remains unchecked) with IE 4.5 - if we want the radio button to be checked, then the correct syntax would be:<input type="radio" checked name="order_type" value="credit"> <!-- for HTML -->
<input type="radio" checked="checked" name="order_type" value="credit"> <!-- for XHTML -->
In any case, if the
order_type[0]
(On-line / Credit Card: ) radio button is checked, then the orderSubmit( ) function calls the order.htm checkCardNumber( ) function, which validates the value of the Credit Card # field<td align="right" bgcolor="#ccffff"><b>Credit Card #:</b></td>
<td bgcolor="#ccffff"><input type="text" size="16" maxlength="16" name="card_no" onblur="checkCardNumber( );"><font size="2"><br>
(no spaces allowed)</font></td>
in the Credit Card Info table. The checkCardNumber( ) function first runs through the Credit Card # characters and checks if they're all digits.
function checkCardNumber( ) {
var i, c, outString = "", retVal = false;
for (i = 0; i < document.order.card_no.value.length; i++) {
c = document.order.card_no.value.charAt(i);
if (c >= "0" && c <= "9") outString += c;
else retVal = true; }
document.order.card_no.value = outString;
/* Credit Card Sanity Check ... */
return retVal; }
For comparison operations involving string literals, Mozilla states,
Strings are compared based on standard lexicographical ordering, using Unicode values.The Unicode code positions for the 0 to 9 digit characters respectively run from U+0030 to U+0039; any and all non-digit characters will fall outside this range and cause the
(c >= "0" && c <= "9")
if condition to return false.If the Credit Card # string contains one or more non-digit characters, then true is assigned to a retVal variable, which at the end of the checkCardNumber( ) function is returned to the orderSubmit( ) function. Back at the orderSubmit( ) function, the
(document.order.order_type[0].checked && checkCardNumber( ))
subcondition returns true and therefore the overall ( ! ((document.order.order_type[0].checked && checkCardNumber( )) || checkRequired( ) || checkExpireDate( )))
if condition returns false, sending control to the else return false;
clause. No explanation is given to the user for why form submission is not successful.If all of the Credit Card # characters are digits, then those characters are used to build an outString string, which is subsequently assigned to the value of the Credit Card # field. Actually, if the Credit Card # string contained a mix of digit and non-digit characters, then checkCardNumber( ) would build and assign to
document.order.card_no.value
an outString string comprising the original string's digit characters, i.e., the non-digit characters would be effectively discarded by the c >= "0" && c <= "9"
operation, e.g., a 432a543b654c765d entry would be converted to 432543654765. If the Credit Card # string contained only non-digit characters, then outString would remain an empty string, which would again be assigned to document.order.card_no.value
, effectively clearing the original entry.In my book, there is no reason to rebuild the Credit Card # value; if we encounter a non-digit character, then we should immediately pop up a relevant alert( ) message,
return true;
, and exit the checkCardNumber( ) function. In moving forward, let us assume that the user enters an all-digit value into the Credit Card # field.You're not my type
As shown in the screen shot at the beginning of the post, the Credit Card Info table contains a Card Type radio button menu of four acceptable credit card options: Visa, MasterCard (M/C), Discover, and American Express (AMEX). After assigning outString to
document.order.card_no.value
, the checkCardNumber( ) function conducts a Credit Card Sanity Checkthat tests for card type-number mismatches via checking the user's Card Type choice against the first
document.order.card_no.value
character.// Credit Card Sanity Check
if (document.order.card_type[0].checked && document.order.card_no.value.charAt(0) != "4") {
window.alert("Please enter a valid VISA number");
retVal = true; }
else if (document.order.card_type[1].checked && document.order.card_no.value.charAt(0) != "5") {
window.alert("Please enter a valid MasterCard number");
retVal = true; }
else if (document.order.card_type[2].checked && document.order.card_no.value.charAt(0) != "6") {
window.alert("Please enter a valid Discover number");
retVal = true; }
else if (document.order.card_type[3].checked && document.order.card_no.value.charAt(0) != "3") {
window.alert("Please enter a valid AMEX number");
retVal = true; }
The common name of the Card Type radio buttons is card_type; the first-in-source-order Visa: option has a
checked=""
attribute and may or may not be initially checked, depending on the browser (vide supra).Visa card numbers always begin with a 4; if the Visa: radio button is checked and the first Credit Card # digit is not a 4, then the if clause displays a Please enter a valid VISA number alert( ) message and assigns true to retVal. The else if clauses analogously handle MasterCard, Discover, and American Express card numbers, which always begin with a 5, 6, and 3, respectively. However, Wikipedia's "Payment card number" entry notes that the first digit of a payment card number identifies a card issuer category and not the card issuer itself: an American Express card number may always begin with a 3, but a card number beginning with a 3 is not necessarily for an American Express card.
12 and over, please
The Credit Card Sanity Check concludes with an else if clause that checks the length of the Credit Card # string.
else if (document.order.card_no.value.length < 12) {
window.alert("The card number you entered is not valid");
retVal = true; }
If the Credit Card # string contains fewer than 12 digits, then a The card number you entered is not valid alert( ) message pops up - better than no message at all, but a Your card number must contain 12-16 digits* message would be more appropriate - and true is assigned to retVal.
*As specified in the I've got your number section above, the Credit Card # field has a
maxlength="16"
attribute that prevents the user from entering more than 16 characters into the field.No freshness date
If the user's Card Type and Credit Card # inputs get through the Credit Card Sanity Check (if all five if conditions return false), then
retVal = false
is returned to the orderSubmit( ) function, causing the (document.order.order_type[0].checked && checkCardNumber( ))
subcondition to return false. The orderSubmit( ) function moves on to the checkRequired( )
subcondition/function, which we discussed in the previous post; if the user's Customer Information / Details and Shipping Address table inputs are in order, then the checkRequired( ) function returns false to the orderSubmit( ) function - two down, one to go. The orderSubmit( ) function finally moves to the checkExpireDate( )
subcondition/function. The order.htm checkExpireDate( ) functionfunction checkExpireDate( ) {
if (document.order.order_type[0].checked) {
if (!document.order.expire_date.value.length) { // If the length is 0
window.alert("Please enter a valid credit card expiration date");
return true; } }
return false; }
returns false - and thereby green-lights the submission of the order form - if the Expiration Date field in the Credit Card Info table
<td align="right" bgcolor="#ccffff"><b>Expiration Date:</b></td>
<td bgcolor="#ccffff"><input type="text" size="16" maxlength="20" name="expire_date" onblur="checkExpireDate( );"><br>
<img src="http://www.mearns.org.uk/scotshop/images/visamast.gif" alt="Cards" width="100" height="30"></td>
has not been left blank. (C'mon, Gordon, we can do better than that.) The checkExpireDate( ) function also returns false if the user has checked the Cheque: or Phone Call: radio button in the Choose Order Method table.
We'll upgrade the checkCardNumber( ) and checkExpireDate( ) functions in the following entry.
Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)