Archive for the ‘javascript’ Category

Retaining browser scrollTop between page refreshes

Tuesday, August 18th, 2009

Sometimes when you develop web applications with CRUD pages and other backend functionalities you need retain the vertical scrollbar state between page loads. This gives the user a smoother experience, especially when your application doesn’t do any AJAX but it’s based of good old full HTML page request-responses.

We’ll be using jQuery and the cookie plugin:

$(function(){
  // if current viewport height is at least 70% of the previous
  if ($(document.body).height()>$.cookie('h2')*0.7)
    // retain previous scroll
    $('html,body').scrollTop($.cookie('h1'));
});
$(window).unload(function(){
  // store current scroll
  $.cookie('h1', $(window).scrollTop());
  // store current viewport height
  $.cookie('h2', $(document.body).height());
});

We can completely skip the h2 cookie and the if statement but this is an automatic way to prevent scrolling to the very bottom of a short page when coming from a long page. Such use case is common when jumping from the “long list of items” to the “edit an item” page.

Good luck

Re: The 140 character webapp challenge!

Saturday, February 14th, 2009

This is my response to The 140 character webapp challenge!

Epilepsy

javascript:{r=0;setInterval(function(){document.body.style.background=(r++%2==0?'#'+r%7+r%9+r%8:'0')},50);void(0)}

114 bytes of inline javascript that you can paste to your browser’s URL.

It’s a very useful webapp* in case you want to cause epilepsy to yourself.

Via: http://f055.net/article/the-140-character-webapp-challenge/
Via: http://synodinos.net/2009/02/14/re-the-140-character-webapp-challenge/

* just kidding :)

Best way to integrate Google Analytics

Thursday, November 6th, 2008

This is the best solution to integrate Google Analytics into your site. It uses ideas and code from the following 2 sites:
http://www.mattiasgeniar.be/webdevelopment/_gat-is-not-defined-google-analytics-error/
http://www.maifith.com/news/_gat-is-undefined-new-analytics-code

Here is the improved snippet:

<script type="text/javascript" src="http://www.google-analytics.com/ga.js"></script>
<script type="text/javascript">
    if (typeof(_gat)=='object')
        setTimeout(function(){
            _gat._getTracker("UA-1234567-8")._trackPageview()}, 1500);
</script>

Improvements:

  1. Does not use document.write
  2. Fixes the “_gat is not defined” issue
  3. Delayed GA access (1.5 second) so the page load time is not affected
  4. Very concise

Another improvement would be to cache ga.js locally to avoid the DNS lookup.

Unit testing JavaScript with JsUnit

Sunday, June 17th, 2007

my-script.js

function capitalize(str) {
  return str?
    str.length>1?str[0].toUpperCase()+str.substring(1):
      str.toUpperCase():str;
}

This is my JavaScript function for capitalizing the first letter of a String. I was sure that I got capitalization right, but I wasn’t too sure about how this function would handle null/empty values.

So I wrote a unit test, for JsUnit:

my-script.test.html

<script language="javascript" src="jsUnitCore.js"></script>
<script language="javascript" src="my-script.js"></script>
<script language="javascript">

function testCapitalize() {
  assertEquals("Foo bar", capitalize("foo bar"));
  assertEquals("Foobar", capitalize("foobar"));
  assertEquals("F", capitalize("f"));
  assertEquals("", capitalize(""));
  assertEquals(JSUNIT_UNDEFINED_VALUE, capitalize(JSUNIT_UNDEFINED_VALUE));
}

</script>

The test requires loading the jsUnitCore.js script. This test loads a local copy but you could use the online version as well. Then I can run the test with my local TestRunner.

Status: Done (0.156 seconds)
Runs: 1   Errors: 0   Failures: 0

Now I know that my function is correct!

When a test fails the assertion error looks like this:

1. my-script.test.html:testCapitalize failed

Expected <Foobar> (String) but was <foobar> (String)

Stack trace follows:
> JsUnitException
> _assert
> assertEquals
> testCapitalize

Happy testing!

Unobtrusive JavaScript

Monday, March 19th, 2007

JavaScript. Yes, it does happen sometimes. Someone asks you to add some client side functionality in your webapp, and you start vomiting js code straight into your (x)html templates. That is very very bad, and you should stop immediately. Since it’s 2007, and given that you want to evolve and keep enjoying what you are doing, here is how you should start thinking about client side code.

Separation of concerns. Years ago, we used to do our presentation inside our (x)html templates. Then we figured our how to do it using CSS. Years ago, we used to do all our persisted data (from database) to Objects translation, inside our POJOs. Then we started using DAOs. Separation is what makes software scale. Unless you are only “engineering” basic contact forms and guestbooks, you should try to embrace separation of concerns and layering, which will make your life easier.

So, back to JavaScript. The idea is to apply your behaviors in an unobtrusive way. Add a class, if necessary, to the elements you want to enhance, and apply the new functionality when the document loads.

Example:

You want to apply duplication functionality in some paragraphs. Clicking on those paragraphs, which have a class “duplicate”, will make them duplicate themselves.

HTML:

<p class="duplicate">Click me!</p>

You’ve got a little piece of nice (x)html. Google does not care what you are going to do on the client side. Screen readers and most mobiles won’t care as well. Why feed them anything more than pure accessible semantic markup? All client side code goes on a separate file, which on load will apply the behavior.

JavaScript:

// when window has loaded
window.onload=init;

  function init() {

  // if browser is capable
  if(document.getElementById) {

    // get all <p>
    var ps = document.getElementsByTagName('p');
    for(var i=0,length=ps.length; i<length; i++) {
    
      // if paragraph element has class 'duplicate'
      if (p[i].className.indexOf('duplicate')>=0) {
    
        // apply behavior
        ps[i].onclick=function() {
          this.parentNode.appendChild(this.cloneNode(true));
        };
      }
    }
  }
}

Live Demo
The first disadvantage here is that we have to write tedious DOM manipulation code. The second is that we have to do browser detection. In this simple example this is not so painful, but when you want to do complex stuff (possibly with asynchronous calls) there will be lots of code for browser compatibility. The third (and most important) problem is that this code will start executing only when the window has finished rendering. In complex documents and slow connections this will be seen.
The answer to all those problems comes with lightweight JavaScript libraries. Have a look at the same code, written in jQuery:

// when window has loaded
$(function(){

  // for all p with class duplicate which will be clicked
  $('p.duplicate').click(function() {

    // apply behavior
    $(this).parent().append($(this).clone());
  })
})

The best advice of course is to avoid use of JavaScript at any cost. IE6, a very popular browser, memory leaks very badly, which is another reason to try and keep JavaScript code to the absolute minimum.
Good luck.