Category Archives: JavaScript

jqPlot Memory Leak

20 Nov 2013

Today I was brought into a conversation with our iOS developer about a portion of a client’s app that utilizes a charting component done in jQuery that is displayed via a web view. TestFlight showed the app crashing during prolonged use of the charting application. The first thing I thought was that memory wasn’t being released so I told the team I would look into it.

I ran the charting app in Chrome and watched the memory usage via the developer tool’s timeline. Sure enough, the familiar memory leak pattern became visible:

jqc_mem_leak_01

Using the tools Chrome provides to isolate a portion of the timeline and investigate what is happening revealed a theme of a “chart()” function being called. I tracked down where that was happening – and in the process discovered that jqPlot was in use (I had no previous experience with the app). I typed in a return statement at a stratgic spot to prevent charting from happening and then proceeded to once again torture the app and review the timeline. As you can see, the memory leak was gone:

jqc_mem_leak_02

No leak – the charting functions are the culprit – a quick search online revealed other people having the issue and one individual mentioning that jqChart has a “destroy” method that releases memory. Perfect, lets review our code again… and yes, all that is happening is that the previous developer is emptying the div wrapper of the chart data before filling it with a new one. That’s not releasing memory.

Here is the code before my edit:

$('#the_chart').html('');
var plot1 = $.jqplot ('the_chart', [fcccPoints, brandXPoints, crossoverPoint],
...

The div wrapper is unceremoniously emptied and the call to jqplot is assigned to a local variable. I needed to keep the reference to the chart so that I can destroy it properly so I moved the variable declaration outside of the function’s scope. I then changed the code to the following:

if (plot1){
    plot1.destroy();
    console.log('plot destroyed');
}
			
$('#the_chart').html('');
plot1 = $.jqplot ('the_chart', [fcccPoints, brandXPoints, crossoverPoint],
...

With those two tiny edits I again torture-tested the app and observed the timeline. As you can see jqPlot’s destroy method was doing its job and memory was now being reclaimed.

jqc_mem_leak_03

On-Device Development in Android

23 Oct 2013

Ever dream about using your Android tablet as a development environment? Android’s ability to use bluetooth keyboards and mice – or even wired USB devices depending on your hardware configuration – removes the usability limitations that instantly come to mind. All that is left is to find the necessary software. For my personal development needs I need three things:

  1. The ability to run a local web server
  2. A text editor, preferably one geared towards development
  3. The ability to debug JavaScript on-device

All three are easily had for free, and better yet, the last one already exists on your device!

Install a web server

This is a requirement for many reasons – the primary one is that it is quite difficult to get Android’s stock web browser to load up a file from the local file system. If you’ve tried you know how much of a pain it is. The second reason is that some of your work is likely to only work off of a web server anyway.

My personal needs require only that I have a functional web sever, however if you search Google Play you’ll find many that support PHP/MySQL so if server-side dev is your thing then you have a few options to choose from.

So again, for my needs a basic web server will suffice and I’ve chosen kWS Android Web Server. Search Google Play for “Web Server” and the app will appear.

After installation you only need to set up the home directory of the server. In my case I created a “www_root” folder on my external SD card where I house my project.

Here’s a screen shot of kWS after I’ve started the server – you can see that it is serving up files from the aforementioned “www_root” directory.

Screenshot_2013-10-16-13-13-32

To reach it you need to start up the Android web browser and enter the IP address for the localhost and the port number that kWS is listening to. That complete URL is:

  • 127.0.0.1:8080

Be sure to have a default file in the root of your home directory such as index.html. If your project file is something else you can easily code in a JavaScript redirect within your index.html to the desired file in order to avoid having to type in the file name that you wish to go to.

Text Editor

As before there are some options to choose from but the one that I have settled on is called DroidEdit Free. It offers code coloring, line numbers, multiple levels of undo, search, goto line and some others. It would be great if it had a linter but I’m not complaining at the moment.

Screenshot_2013-10-16-11-08-45

JavaScript Debugger

The stock android web browser has a console that will display errors, console.log statements and even allow for in-console commands to be entered. The trick is how to enable it since by default you cannot see the Debug option within the browser’s settings.

Its really quite simple to enable – once you are looking at your project via your newly installed web server type the following in the address bar:

  • about:debug

Nothing will appear to have changed but you’ve just enabled the JavaScript Console. It will appear if you’ve logged any statements or if there is an error in your code. It appears as a thin black bar – tap the bar to expand the console. In the example below you can see an error being logged at line 21:

Screenshot_2013-10-16-13-24-33

Errors will be logged but unfortunately you cannot inspect objects like is possible with desktop-class browsers and remote debuggers. This behaves much like the Adobe AIR CMD debug console if you’ve ever seen it – very basic. Nevertheless just being able to see errors with their associated line numbers is very useful.

You can configure additional debug options via the new Debug option in the browser settings. The defaults work fine for me.

Screenshot_2013-10-16-10-27-16

Conclusion

As time moves on mobile OS’s are getting more and more capable and have in many respects replaced mainstream “desktop” OS’s. This is just another example of that phenomenon. If you know of any other tools that should replace what I’ve listed above feel free to let me know. The key though is that everything should be **local** to the device.

As an aside, to get more out of your development you may want to download an FTP client and a File Manager. Two great options are Es File Manager and Astro which combine both of these features. I suspect though that you are already using one of these 😉

Mixing jQuery and reCaptcha in Forms

06 Oct 2013

The business of collecting user data includes the ubiquitous form. The thing with forms is that they are the first to see abuse on the Internet and if left unprotected your inbox or database will soon be overrun with spam. One of many methods of protecting forms is the CAPTCHA. CAPTCHAs require that a user interpret a randomly-generated image by typing its value into a text field. Since automated programs (bots) can’t read the image they are stopped cold. Humans and their famously short attention spans happen to have enough bandwidth to tolerate a CAPTCHA or two. The Spammer variants, on the other hand, seem to lack the patience needed and will quickly move on to easier pickings of which there are untold thousands. So then, while a CAPTCHA is a minor inconvenience to your end-users it’s presence more than makes up for itself by its ability to completely stave off an avalanche of useless form posts.

Google provides a CAPTCHA service called reCAPTCHA which is the subject of this article.

The workflow I’ll be implementing is the following:

  1. User “submits” form
  2. The form is validated
  3. If form validation succeeds I then make an AJAX call to the reCaptcha service via a proxy to see if the user entered the correct reCaptcha value
  4. If an incorrect value was entered I’ll display an in-line message to the user
  5. If the correct value was entered I will submit the form

You can see this process in action below:

Register for a set of reCAPTCHA keys

You must first sign up to use reCAPTCHA by visiting http://www.google.com/recaptcha. After you register click the “Add Site” link and add your site. After you add a site you will get 2 keys – keep these handy, we’ll need them later.

Download the reCAPTCHA PHP Library

You will also need to download the reCAPTCHA PHP Library (I’m assuming that your site is on a PHP-compatible server).

Setting up a proxy

Since we plan on making AJAX calls to the reCAPTCHA service we know we will need a proxy as we would otherwise run afoul of the browser’s cross-domain policy. The way we will circumvent this is by creating a proxy. This proxy will handle communication between our web page and reCAPTCHA by forwarding our submitted form data to the reCAPTCHA service which in return responds to the proxy and then the proxy hands the response back to our web page.

The reCAPTCHA PHP library contains everything we need to setup our proxy. The library contains 5 files – we will be using 2 of them:

  • recaptchalib.php
  • example-captcha.php

The second file – example-captcha.php – will need to be modified for our purposes. Here is the original file (this is version 1.11) before any changes:

<html>
  <body>
    <form action="" method="post">
<?php

require_once('recaptchalib.php');

// Get a key from https://www.google.com/recaptcha/admin/create
$publickey = "";
$privatekey = "";

# the response from reCAPTCHA
$resp = null;
# the error code from reCAPTCHA, if any
$error = null;

# was there a reCAPTCHA response?
if ($_POST["recaptcha_response_field"]) {
        $resp = recaptcha_check_answer ($privatekey,
           $_SERVER["REMOTE_ADDR"],
           $_POST["recaptcha_challenge_field"],
           $_POST["recaptcha_response_field"]);

        if ($resp->is_valid) {
            echo "You got it!";
        } else {
             # set the error code so that we can display it
             $error = $resp->error;
        }
}
echo recaptcha_get_html($publickey, $error);
?>
    <br/>
    <input type="submit" value="submit" />
    </form>
  </body>
</html>

To get to where we need to be we need to remove all html and make a couple of tiny changes to the PHP. I won’t walk through them in detail opting instead to just show you the finished edited file (the savvy among you will no doubt notice the differences) and to mention that the public and private reCAPTCHA keys are in use here:

<?php

require_once('recaptchalib.php');

// Get keys from https://www.google.com/recaptcha/admin/create
$publickey = "YOUR_PUBLIC_KEY_HERE";
$privatekey = "YOUR_PRIVATE_KEY_HERE";

# the response from reCAPTCHA
$resp = null;

# was there a reCAPTCHA response?
if ($_POST["recaptcha_response_field"]) {
    $resp = recaptcha_check_answer ($privatekey,
        $_SERVER["REMOTE_ADDR"],
        $_POST["recaptcha_challenge_field"],
        $_POST["recaptcha_response_field"]);

    if ($resp->is_valid) {
        echo "success";
    } else {
        echo "failure";
    }
}
?>

The line that echoes “success” is what we will be listening for in our AJAX call to determine if the reCAPTCHA verification was successful.

At this point your proxy is done. Go ahead and place your modified example-captcha.php and the unchanged recaptchalib.php on your server in the same folder as your form.

Add the jQuery and reCAPTCHA JS Libraries

You need to add these two lines within the head of your document (use whatever version of jQuery your project requires):

...
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js">
<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js">
...

Setting up your form

The form code below is pretty basic – things to pay attention to:

  • This is a template for the reCAPTCHA functionality only – you still need to configure your form to work with your form remailer (i.e., gdform.php on GoDaddy, formmail.php, cgiemail or whatever the case might be)
  • Note the onsubmit=”return doForm()” in the FORM tag – this is the hook to our JavaScript that communicates to the reCAPTCHA server
  • There are 2 divs present:

    • <div id=”recap”></div> this is the wrapper for the reCaptcha itself
    • <div id=”err”>…</div> This is the in-line error message that we will display if the reCAPTCHA verification fails.
       
  • Note the style tag – we have a css class called “hidden” that is assigned to the reCAPTCHA error div. If there is an error we use jQuery to remove the class and show the error message to the user
     
...
<style type="text/css">
    /* place the style in your stylesheet or move this to the head of your document */
    .hidden{
        display:none;
    }
</style>

<!-- note the onsubmit="return doForm()" - your FORM tag must contain this -->
<form action="test.php" method="post" name="form1" id="form1" onsubmit="return doForm()">

    <!-- your form fields would go in here -->
    Name: <input class="textInput" name="Name" type="text" id="name" size="55" maxlength="55" />

    <!-- The reCAPTCHA wrapper is here - this is required!! -->
    <div id="recap"></div>

    <!-- the reCAPTCHA error div is next, edit/style as you see fit -->
    <div id="err" class="hidden" style="background-color:#FFFF00;color:#FF0000;margin:12px 0px 12px 0px;">The Captcha was not entered correctly. Please try again.</div>

    <!-- the submit button -->
    <input type="submit" name="button" id="button" value="Submit" />
</form>
...

Inserting the reCAPTCHA, validating Form and reCAPTCHA input

Next we need to insert the reCAPTCHA elements into the document. In the code that follows you can see that I’m inserting the reCAPTCHA on jQuery’s document.ready event.

When the form is submitted I first validate the form input which you can see in the doForm() function. If validation passes I then attempt to validate the reCAPTCHA via the recapVerify function.

Its all put together in the code snippet below (** add your public key where indicated in line 41 **):

...
<script type="text/javascript">

    // VALIDATE THE FORM
    function doForm(){
	// your form validation would go here, for example:
	var isValid = $('#name').val().length != 0 ? true : false;

	if (!isValid){ // FORM VALIDATION FAILED
	    alert('Name is required');

	} else { //FORM VALIDATION SUCCEEDED, validate the reCAPTCHA
	    recapVerify(); // verify reCAPTCHA
	}
	return false;
    }

    // VALIDATE THE reCAPTCHA
    function recapVerify(){
        $.ajax({
	    type:'post',
	    url: 'captcha_proxy.php',
	    data: {
	        recaptcha_challenge_field:$('#recaptcha_challenge_field').val(),
	        recaptcha_response_field:$('#recaptcha_response_field').val()
	    }
	}).done(function(data, textStatus, jqXHR){
	    if (data == 'success'){
	        $('#err').addClass('hidden');
	        document.forms[0].submit();
	    } else {
	        $('#err').removeClass('hidden');
	    }
	}).fail(function(jqXHR,textStatus,errorThrown){
            console.log('proxy or service failure');
	});
    }

    // WHEN CALLED THIS INSETS THE reCAPTCHA INTO THE PAGE
    function reCapInsert(){
        Recaptcha.create('YOUR_PUBLIC_KEY_HERE',  // public key
        'recap',
            {
                theme: 'clean',
                callback: Recaptcha.focus_response_field
            }
	);
    }

    // WHEN THE DOM HAS LOADED FIRE THE reCapInsert FUNCTION TO INSERT THE reCAPTCHA
    $( document ).ready(function(){
        reCapInsert();
    });
	
</script>
...

And that should do it. Download all files here.

Before they leave – warning users of unintended consequences

26 Sep 2013

Warning a user about to leave your page that doing so will result in lost data is easily achieved via the window.onbefureunload event. Returning a string will trigger the web browser’s default functionality for warning the user before they navigate away from your page.

The behavior differs slightly from browser to browser. I’ll get into how each browser handles it in a moment, but first here’s the code:

window.onbeforeunload = function(){
    return 'Place your message here';
}

Very easy – by simply returning a string a web browser will interpret this as a warning to the user that they might lose data by leaving. In some browsers your returned string is used within the message prompt in addition to the browser’s own warning while in others (FireFox in both Windows and OSX) your message text is not used at all in favor of the browser’s default message. Following are screen captures of how various browsers in Windows and OSX handle the onbeforeunload event.

Chrome in Windows displays your message in addition to text of its own:

obu_win_chrome

Internet Explorer 7+ displays the message like this:

obu_win_ie9

Firefox in Win Vista displays its own message box that does not contain your message text:

obu_win_ff

Chrome in OSX displays your custom message in this manner:

obu_osx_chrome

Firefox on OSX behaves similarly to its Windows version by not displaying your custom message:

obu_osx_2ff

Finally, Safari in OSX shows your message and includes the URL of the page you are about to leave:

obu_osx_2safari

Mobile Device Detection using the UserAgent

26 Jun 2013

It used to be that you could use css media queries on mobile devices due to the limited screen resolutions available. We knew, for instance, that 480 x 320 was the iPhone’s screen resolution so you could do a media query based on those dimensions and deliver a phone layout, or the 1024×768 resolution was a tablet – which is funny because the iPhone 5 is 1136×640 – so, what is your media query going to do then? Even today designers are making assumptions about the break points for their media queries and there continues to be debate on the topic. I wonder why all the fuss when as time moves on the subject only just gets more confusing and debatable as higher resolutions are no longer solely in the realm of tablets. Today the gamut of resolutions varies to such an extent that you cannot assume that resolution x is a phone or resolution y is a tablet.

IMO if you’re trying to figure out which style sheet to apply you need to first know the sort of mobile device you’re dealing with as that gives you a better idea about the relative physical size of the device to begin with.

The way to do this is via the navigator object’s userAgent property. For iOS things are pretty simple – look for the presence of “iOS” and you know you are dealing with an Apple device. Look for “iPhone” and “iPad” and you know if you have an Apple phone or an Apple tablet.

For Android its mostly just as simple. I say mostly because not every manufacturer sticks to Google’s requirement that the word “Mobile” be present in all Android phone-specific UA strings. Even with that caveat this makes it possible for us to discern an Android phone from an Android tablet.

To take things a step further, you’ll also need to know the Android version numbers as you may find it neccessary to code against specific versions of Android – even within the minor versions – in order to make your app work as desired (or degrade as desired, as the case may be).

So then below you will find my take at this – it is a function that creates an object that contains everything that you may want. At the very least it contains everything that I personally find helpful.

Here’s the code:

...
    var _deviceInfo = {
        ios:false,
        android:false,
        iphone:false,
        ipad:false,
        androidTablet:false,
        androidPhone:false,
        isPhone:false,
        isTablet:false,
        isDesktop:false,
        pixeldensity:1,
        androidVersion:{full:null,major:null,minor:null,revision:null}
    };
	
    (function(){
        var ua = navigator.userAgent.toLowerCase();
        var pf = navigator.platform.toLowerCase();
        var iosTest = /mac.+mobile/gi;
        var andTest = /android/gi;
        var iPhoneTest = /iphone/gi;
        var iPadTest = /ipad/gi;
        var mobile = /mobile/gi;
        var desktopWin = /win/;
        var desktopOSX = /mac/;
        var deviceHeight = window.innerHeight;
        var deviceWidth = window.innerWidth;
        var androidUAVer = /[android\s](\d\.\d\.\d){1}/;
		
        if (iosTest.test(navigator.userAgent)){
            _deviceInfo.ios = true;
        }
        if (andTest.test(navigator.userAgent)){
            _deviceInfo.android = true;
        }
        if (iPhoneTest.test(navigator.userAgent)){
            _deviceInfo.iphone = true;
            _deviceInfo.isPhone = true;
        }
        if (iPadTest.test(navigator.userAgent)){
            _deviceInfo.ipad = true;
            _deviceInfo.isTablet = true;
        }
        if (ua.indexOf('android') != -1 && ua.indexOf('mobile') == -1){
            _deviceInfo.androidTablet = true;
            _deviceInfo.isTablet = true;
        }
        if (ua.indexOf('android') != -1 && ua.indexOf('mobile') != -1){
            _deviceInfo.androidPhone = true;
            _deviceInfo.isPhone = true;
        }
        if(desktopWin.test(pf) || desktopOSX.test(pf)){
            _deviceInfo.isDesktop = true;
        }
        if (_deviceInfo.android){
            var andVer = ua.match(androidUAVer)[1];
            var parts = andVer.split('.');
            _deviceInfo.androidVersion.full = andVer;
            _deviceInfo.androidVersion.major = parts[0]; 
            _deviceInfo.androidVersion.minor = parts[1];
            _deviceInfo.androidVersion.revision = parts[2];
        }
        if (window.devicePixelRatio){
            _deviceInfo.pixeldensity = window.devicePixelRatio;
        }
    })();
...

Ideally you drop the above within your app’s namespace, but once you have it incorporated within your project you can use the _deviceInfo object to learn about the device in question. Take a look at the object declaration at the top – its obvious what you can get out of it.

Note that the isPhone and isTablet properties are just generic “phone” and “tablet” flags and work for both iOS and Android. If you want to get specific, then use the platform specific properties where iphone and ipad are obviously those devices and androidTablet and androidPhone are what their titles infer.

An example application of this is writing device-specific style sheets into your Web app (add break-points for the specific device if you’re so inclined):

...
    (function(){
        var _d = your_name_space.getDeviceInfo();
        if (_d.isTablet && _d.ios){
            document.write('');
        }
        if (_d.isTablet && _d.android){
            document.write('');
        }
        if (_d.iphone){
            document.write('');
        }
        if (_d.isPhone && _d.android){
            document.write('');
        }
    })();
...

Together with responsive layouts the above should serve you well.

Another way to make use of this script is for device-specific feature enablement such as in this case where I’m setting application-wide features in jQuery Mobile:

...
    var _d = your_name_space.getDeviceInfo();
    $.extend( $.mobile,{
        defaultDialogTransition: (_d.android ? 'none' : 'pop'),
        defaultPageTransition: (_d.android ? 'none' : 'fade'),
    });
...