B4X: ABMaterials B4JS – 03 Inline Javascript

B4JSTut03

This is another one of those fantastic B4X features that I wanted in B4JS: Inline Javascript.

Just like its big brothers, you can easily put javascript functions in a B4JS class. This last part is important: you can ONLY declare it in a B4JS class. But, as we will see further, you will be able to call the method in your normal ABM Page class.

So, suppose we found a nice method in Javascript to check a credit card. In your B4JS class, you can use #If JAVASCRIPT and #End If to define a javascript region. You can add multiple methods in one block if you want.

Public Sub InitializeB4JS
   Page.B4JSRunMethod("B4JSCalculateDistance", "cHECKCard", Array As String("5105105105105100"))
   Page.B4JSRunMethod("B4JSCalculateDistance", "CheckCard", Array As String("111111"))
End Sub

public Sub CheckCard(cardNumber As String)
   Dim isValid As Boolean = Page.B4JSRunInlineJavascriptMethod("validateCCNum", Array As Object(cardNumber))
   If isValid Then
       Log("Card '" & cardNumber & "' is a valid card. Please continue...")
   Else
       Log("Card '" & cardNumber & "' is NOT valid. Please check the number...")
   End If
End Sub
#If JAVASCRIPT
function validateCCNum(ccnum) {
   var ccCheckRegExp = /[^\d\s-]/;
    var isValid = !ccCheckRegExp.test(ccnum);
    var i;
    if (isValid) {
        var cardNumbersOnly = ccnum.replace(/[\s-]/g,"");
        var cardNumberLength = cardNumbersOnly.length;
        var arrCheckTypes = ['visa', 'mastercard', 'amex', 'discover', 'dinners', 'jcb'];
        for(i=0; i<arrCheckTypes.length; i++) {
            var lengthIsValid = false;
            var prefixIsValid = false;
            var prefixRegExp;
            switch (arrCheckTypes[i]) {
                case "mastercard":
                    lengthIsValid = (cardNumberLength === 16);
                    prefixRegExp = /^5[1-5]/;
                    break;
                case "visa":
                    lengthIsValid = (cardNumberLength === 16 || cardNumberLength === 13);
                    prefixRegExp = /^4/;
                    break;
                case "amex":
                    lengthIsValid = (cardNumberLength === 15);
                    prefixRegExp = /^3([47])/;
                    break;
                case "discover":
                    lengthIsValid = (cardNumberLength === 15 || cardNumberLength === 16);
                    prefixRegExp = /^(6011|5)/;
                    break;
                case "dinners":
                    lengthIsValid = (cardNumberLength === 14);
                    prefixRegExp = /^(300|301|302|303|304|305|36|38)/;
                    break;
                case "jcb":
                    lengthIsValid = (cardNumberLength === 15 || cardNumberLength === 16);
                    prefixRegExp = /^(2131|1800|35)/;
                    break;
                default:
                    prefixRegExp = /^$/;
            }
            prefixIsValid = prefixRegExp.test(cardNumbersOnly);
            isValid = prefixIsValid && lengthIsValid;

            // Check if we found a correct one
            if(isValid) {
                break;
            }
        }
    }

    if (!isValid) {
        return false;
    }

    // Remove all dashes for the checksum checks to eliminate negative numbers
    ccnum = ccnum.replace(/[\s-]/g,"");
    // Checksum ("Mod 10")
    // Add even digits in even length strings or odd digits in odd length strings.
    var checksum = 0;
    for (i = (2 - (ccnum.length % 2)); i <= ccnum.length; i += 2) {
        checksum += parseInt(ccnum.charAt(i - 1));
    }

    // Analyze odd digits in even length strings or even digits in odd length strings.
    for (i = (ccnum.length % 2) + 1; i < ccnum.length; i += 2) {
        var digit = parseInt(ccnum.charAt(i - 1)) * 2;
        if (digit < 10) {
            checksum += digit;
        } else {
            checksum += (digit - 9);
        }
    }

    return (checksum % 10) === 0;
}
#End If

The result in the browsers log:

Card '5105105105105100' is a valid card. Please continue...
Card '111111' is NOT valid. Please check the number...

Pretty cool no? :)

A couple of things we see here in the code (besides the #if JAVASCRIPT part.

1. Calling a javascript function in your B4JS code using Page.B4JSRunInlineJavascriptMethod:

Dim isValid As Boolean = Page.B4JSRunInlineJavascriptMethod("validateCCNum", Array As Object(cardNumber))

It is VERY important (unlike we are used in B4J, that the method name (here validateCCNum) matches the case. e.g. VAlidateCCNum will NOT work!

2. Calling a B4JS function in your B4JS code using Page.B4JSRunMethod:

Page.B4JSRunMethod("B4JSCalculateDistance", "cHECKCard", Array As String("5105105105105100"))

And we’re back on familiar B4X ground :) The case of the method (or class) does not matter as all is lowercased anyway. Why do we have to mention the class, I hear you think. Well this is because we can call a method from ANOTHER B4JS class too!

And moreover, we can also call these methods in our normal ABM webpage!

sub ConnectPage()
 ...
' method 1: calling our own B4JS sub and handeling the result on thebrowser side
   page.B4JSRunMethod("B4JSCalculateDistance", "cHECKCard", Array As String(CardNumber))

   ' method 2: directly calling the Javascript function and handeling the result on the server side
   Dim isValid As Boolean = page.B4JSRunInlineJavascriptMethod("validateCCNum", Array As Object(CardNumber))
   If isValid Then
       Log("Server Card '" & CardNumber & "' is a valid card. Please continue...")
   Else
       Log("Server Card '" & CardNumber & "' is NOT valid. Please check the number...")
   End If
   ...
End Sub

So the result of method 1 (in the Browser log):

Card '5105105105105100' is a valid card. Please continue...
Card '111111' is NOT valid. Please check the number...

And the result of method 2 (in the B4J log):

Server Card '5105105105105100' is a valid card. Please continue...

In the next tutorial (04 – Running Javascript on the server side) I’ll show how you can even run this on the server side, not even needing a browser open. :p

A final note: #if JAVASCRIPT regions do not really belong to the class. They are shared between all B4JS classes you create.

Happy programming!

Alwaysbusy

Click here to Donation and support ABMaterial

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s