JavaScript Style: Whitespace

Introduction

Image from   Pluralsight

Image from Pluralsight

Good code is not just functional, but also elegant. Elegant code must be:

In a series of posts, we'll discuss coding style for the JavaScriptlanguage. In this second post, we'll focus on style guidelines for whitespace.

Summary

The style guidelines for JavaScript whitespace are broken down into the following categories:

  • Indentation
  • Spaces Around
  • Spaces Before
  • Spaces After
  • Spaces Not Allowed
  • Blank Lines
  • Other

Each category is is explained below. Must you follow these guidelines? No. Should you? Yes.

Indentation

The indentation guidelines for JavaScript are:

  • Require indentation with four (4) spaces
  • Disallow tabs for indentation

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    function Log() {

        var now,                //  current date/time
            elapsed,            //  elapsed milliseconds since we initialized the stats
            messagesPerSec,     //  number of messages/sec since initialization
            charsPerSec,        //  number of message character/sec since initialization
            idList,             //  the comma-delimited list of ids
            prop;               //  an object property

        now = Now();
        elapsed = now - this.start;
        messagesPerSec = ( this.messages / ( elapsed / 1000 ) );
        charsPerSec = ( this.chars / ( elapsed / 1000 ) );

        for ( prop in this.ids ) {
            if ( this.ids.hasOwnProperty( prop ) ) {
                if ( !idList ) {
                    idList = prop;
                } else {
                    idList = idList + "," + prop;
                }
            }
        }

        options.log( "SOCKET(" + idList + "): Stats - " + messagesPerSec.toFixed( 1 ) + " msg/sec, " + charsPerSec.toFixed( 0 ) + " char/sec" );
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    function Log() {

      var now,              //  current date/time
        elapsed,            //  elapsed milliseconds since we initialized the stats
        messagesPerSec,     //  number of messages/sec since initialization
        charsPerSec,        //  number of message character/sec since initialization
        idList,             //  the comma-delimited list of ids
        prop;               //  an object property

      now = Now();
      elapsed = now - this.start;
      messagesPerSec = ( this.messages / ( elapsed / 1000 ) );
      charsPerSec = ( this.chars / ( elapsed / 1000 ) );

      for ( prop in this.ids ) {                  
        if ( this.ids.hasOwnProperty( prop ) ) {
          if ( !idList ) {
            idList = prop;                  //  BAD: indentation uses two (2) spaces
          } else {                          //  BAD: indentation uses tabs (trust me on this one)
            idList = idList + "," + prop;
          }
        }
      }

      options.log( "SOCKET(" + idList + "): Stats - " + messagesPerSec.toFixed( 1 ) + " msg/sec, " + charsPerSec.toFixed( 0 ) + " char/sec" );
    }

Spaces Around

Spaces are required around:

  • The content of square brackets - []
  • The content of parentheses - ()
  • The content of curly braces - {}
  • Infix operators

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    function getDaysInMonth( month, year ) {

        var monthDays,
            days;

        monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

        if ( month === 2 ) {

            // february, taking leap years into account
            if ( year % 400 === 0 ) {
                days = 29;
            } else if ( ( year % 4 === 0 ) && ( year % 100 !== 0 ) ) {
                days = 29;
            } else {
                days = 28;
            }
        } else {

            //  all other months
            days = monthDays[ month - 1 ];
        }

        return { "days": days };
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    function getDaysInMonth(month, year) {

        var monthDays,
            days;

        monthDays=[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

        if (month===2) {                //  BAD: no spaces around () content

            // february, taking leap years into account
            if (year%400===0) {
                days=29;
            } else if ((year%4===0)&&(year%100!==0)) {
                days=29;
            } else {
                days=28;                //  BAD: no spaces around infix operator
            }
        } else {

            //  all other months
            days=monthDays[month-1];    //  BAD: no spaces around [] content
        }

        return {"days": days};          //  BAD: no spaces around {} content
    }

Spaces Before

Spaces are required before:

  • Blocks
  • Keywords (break, catch, class, const, continue, do, else, finally, for, function, if, let, return, switch, throw, try, var, while, with, yield)
  • Object literal property values

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    function getDaysInMonth( month, year ) {

        var monthDays,
            days;

        monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

        if ( month === 2 ) {

            // february, taking leap years into account
            if ( year % 400 === 0 ) {
                days = 29;
            } else if ( ( year % 4 === 0 ) && ( year % 100 !== 0 ) ) {
                days = 29;
            } else {
                days = 28;
            }
        } else {

            //  all other months
            days = monthDays[ month - 1 ];
        }

        return { "days": days };
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    function getDaysInMonth( month, year ){

        var monthDays,
            days;

        monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

        if ( month === 2 ){                                 //  BAD: no space before block

            // february, taking leap years into account
            if ( year % 400 === 0 ){
                days = 29;
            }else if ( ( year % 4 === 0 ) && ( year % 100 !== 0 ) ){
                days = 29;
            }else{
                days = 28;
            }
        }else{                                              //  BAD: no space before "else" keyword

            //  all other months
            days = monthDays[ month - 1 ];
        }

        return{ "days":days };                              //  BAD: no space before object literal property value
    }

Spaces After

Spaces are required after:

  • Commas
  • Semicolons
  • Keywords (case, catch, do, else, finally, for, if, return, switch, throw, try, while, with)
  • Unary word operators (delete, new, typeof, void, yield)
  • Start of comments

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
    function ApplyConfigToWidgets() {

        var config,
            ids,
            i;

        config = gConfig;
        ids = [];

        if ( config && config.widgets ) {

            //  load proper content into each widget, via ajax
            for ( i = 0; i < config.widgets.length; i++ ) {

                //  define a closure to isolate state instance
                ( function( state ) {

                    var method,
                        code,
                        config,
                        $placeholder,
                        start,
                        stop;

                    if ( "swatWidgetType" in state ) {

                        //  extract information from state
                        code = state.swatWidgetType.replace( /^sw-/, "" );
                        method = state.swatWidgetType.replace( /^sw-dashboard/, "" );
                        config = state.swatConfig;

                        //  locate placeholder
                        $placeholder = $( "#" + ids[ i ] );

                        //  load widget content via ajax
                        LoadWidgetViaAjax( {
                            "$container": $placeholder,
                            "code": code,
                            "method": method,
                            "config": config
                        } );
                    }
                } )( config.widgets[ i ] );
            }
        }
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    function ApplyConfigToWidgets() {

        var config,ids,i;                                       //  BAD: no space after commas

        config = gConfig;
        ids = [];

        if( config && config.widgets ) {

            //load proper content into each widget, via ajax
            for( i = 0;i < config.widgets.length;i++ ) {        //  BAD: no space after semicolons

                //define a closure to isolate state instance
                ( function( state ) {

                    var method,code,config,$placeholder,start,stop;

                    if( "swatWidgetType" in state ) {           //  BAD: no space after keyword

                        //extract information from state
                        code = state.swatWidgetType.replace( /^sw-/,"" );
                        method = state.swatWidgetType.replace( /^sw-dashboard/,"" );
                        config = state.swatConfig;

                        //locate placeholder                    //  BAD: no space after start of comment
                        $placeholder = $( "#" + ids[ i ] );

                        //load widget content via ajax
                        LoadWidgetViaAjax( {
                            "$container": $placeholder,
                            "code": code,
                            "method": method,
                            "config": config
                        } );
                    }
                } )( config.widgets[ i ] );
            }
        }
    }

Spaces Not Allowed

Spaces are not allowed:

  • Before commas
  • Before semicolons
  • Before another space (i.e. multiple spaces)
  • Before the opening parenthesis of a function (definition or call)
  • After unary non-word operators (-, +, --, ++, !, !!)

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
    function ApplyConfigToWidgets() {

        var config,
            ids,
            i;

        config = gConfig;
        ids = [];

        if ( config && config.widgets ) {

            //  load proper content into each widget, via ajax
            for ( i = 0; i < config.widgets.length; ++i ) {

                //  define a closure to isolate state instance
                ( function( state ) {

                    var method,
                        code,
                        config,
                        $placeholder,
                        start,
                        stop;

                    if ( "swatWidgetType" in state ) {

                        //  extract information from state
                        code = state.swatWidgetType.replace( /^sw-/, "" );
                        method = state.swatWidgetType.replace( /^sw-dashboard/, "" );
                        config = state.swatConfig;

                        //  locate placeholder
                        $placeholder = $( "#" + ids[ i ] );

                        //  load widget content via ajax
                        LoadWidgetViaAjax( {
                            "$container": $placeholder,
                            "code": code,
                            "method": method,
                            "config": config
                        } );
                    }
                } )( config.widgets[ i ] );
            }
        }
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
    function ApplyConfigToWidgets () {

        var config ,                                            //  BAD: space before comma
            ids ,
            i ;                                                 //  BAD: space before semicolon

        config = gConfig ;
        ids    = [] ;                                           //  BAD: space before space (multiple spaces)

        if ( config && config.widgets ) {

            //  load proper content into each widget , via ajax
            for ( i = 0 ; i < config.widgets.length ; ++ i ) {  //  BAD: space after unary non-word operator (++)

                //  define a closure to isolate state instance
                ( function ( state ) {                          //  BAD: space before function ()s

                    var method ,
                        code ,
                        config ,
                        $placeholder ,
                        start ,
                        stop ;

                    if ( "swatWidgetType" in state ) {

                        //  extract information from state
                        code = state.swatWidgetType.replace ( /^sw-/ , "" ) ;
                        method = state.swatWidgetType.replace ( /^sw-dashboard/ , "" ) ;
                        config = state.swatConfig ;

                        //  locate placeholder
                        $placeholder = $( "#" + ids[ i ] ) ;

                        //  load widget content via ajax
                        LoadWidgetViaAjax ( {
                            "$container": $placeholder ,
                            "code":       code ,
                            "method":     method ,
                            "config":     config
                        } ) ;
                    }
                } ) ( config.widgets[ i ] ) ;
            }
        }
    }

Blank Lines

Blank lines are required:

  • After a `var` statement
  • Before a comment
  • At the end of the file

Blank lines are not allowed:

  • After a comment
  • After a blank line (e.g. multiple blank lines)

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    function getDaysInMonth( month, year ) {

        var monthDays,
            days;

        monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

        if ( month === 2 ) {

            // february, taking leap years into account
            if ( year % 400 === 0 ) {
                days = 29;
            } else if ( ( year % 4 === 0 ) && ( year % 100 !== 0 ) ) {
                days = 29;
            } else {
                days = 28;
            }
        } else {

            //  all other months
            days = monthDays[ month - 1 ];
        }

        return { "days": days };
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    function getDaysInMonth( month, year ) {

        var monthDays,
            days;                                           //  BAD: missing blank line after `var` statement
        monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];

        if ( month === 2 ) {
            // february, taking leap years into account     //  BAD: missing blank line before comment
                                                            //  BAD: blank line after comment
            if ( year % 400 === 0 ) {
                days = 29;
            } else if ( ( year % 4 === 0 ) && ( year % 100 !== 0 ) ) {
                days = 29;
            } else {
                days = 28;
            }
        } else {
            //  all other months

            days = monthDays[ month - 1 ];
        }

                                                            //  BAD: multiple blank lines

        return { "days": days };
    }                                                       //  BAD: missing blank line at end of file

Other

Other whitespace guidelines for JavaScript are:

  • Use consistent line breaks
  • Avoid irregular whitespace characters (e.g. zero width space, non-breaking space, vertical tab, etc.)

By definition, line breaks and irregular whitespace characters are invisible, so we can't provide a meaningful visual example here.

Next time

Function conventions.

Source: http://www.finitewisdom.com/people/joshua-...

JAVASCRIPT STYLE : VARIABLES

Image from  Pluralsight

Image from Pluralsight

Introduction

Good code is not just functional, but also elegant. Elegant code must be:

In a series of posts, we'll discuss coding style for the JavaScript language. In this first post, we'll focus on style guidelines for variables.

Summary

The style guidelines for JavaScript variables are:

  • Declare all variables at the top of the function
  • Use a single var statement
  • Document the meaning of each variable
  • Separate variable initialization from variable declaration
  • Use CamelCase starting with a lowercase letter
  • "Apps Hungarian" notation is acceptable; "System Hungarian" is not

Each guideline is explained below. Must you follow these guidelines? No. Should you? Yes.

Declare all variables at the top of the function

In JavaScript, all variables have function scope, not block scope. We declare all variables at the top of the function to make this explicit and avoid misleading the reader with a variable that looks like it has block scope.

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
    /**
     * Is the connection silent? If we haven't received any messages in the silence interval,
     * then we are.
     *
     * @return {boolean} Is the connection silent?
     */
    function Silent() {

        var now,        //  current date/time (GOOD)
            silent;     //  is the connection silent?

        now = new Date();
        silent = false;

        if ( myLastWebSocketMessageDate ) {
            if ( now - myLastWebSocketMessageDate > options.intervals.silence ) {
                silent = true;
            }
        }

        return silent;
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
    /**
     * Is the connection silent? If we haven't received any messages in the silence interval,
     * then we are.
     *
     * @return {boolean} Is the connection silent?
     */
    function Silent() {

        var silent;     //  is the connection silent?

        silent = false;

        if ( myLastWebSocketMessageDate ) {
            var now = new Date(); // BAD
            if ( now - myLastWebSocketMessageDate > options.intervals.silence ) {
                silent = true;
            }
        }

        return silent;
    }

Learn more about variable scope.

Use a single var statement

Use a single var statement for all variables in a function. Do not use one var statement per variable.

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
    /**
     * Is the connection silent? If we haven't received any messages in the silence interval,
     * then we are.
     *
     * @return {boolean} Is the connection silent?
     */
    function Silent() {

        var now,        //  current date/time (GOOD)
            silent;     //  is the connection silent?

        now = new Date();
        silent = false;

        if ( myLastWebSocketMessageDate ) {
            if ( now - myLastWebSocketMessageDate > options.intervals.silence ) {
                silent = true;
            }
        }

        return silent;
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
    /**
     * Is the connection silent? If we haven't received any messages in the silence interval,
     * then we are.
     *
     * @return {boolean} Is the connection silent?
     */
    function Silent() {

        var now;        //  current date/time
        var silent;     //  is the connection silent? (BAD)

        now = new Date();
        silent = false;

        if ( myLastWebSocketMessageDate ) {
            if ( now - myLastWebSocketMessageDate > options.intervals.silence ) {
                silent = true;
            }
        }

        return silent;
    }

Learn more about why a single var statement is good.

Document the meaning of each variable

Unless the meaning of a given variable is intuitively clear (e.g. headerHeight for the height of a header), then use an inline comment to document the meaning of the variable.

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    function GenerateUpdateEventsForMetrics( a ) {

        var i,          //  the array index
            metric,     //  one metric in the array (GOOD)
            events,     //  an object representing an associative array of events
            zones;      //  the codes for the warning and danger zones

        events = {};
        zones = [ "", "warning", "danger" ];

        //  code omitted for clarity
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    function GenerateUpdateEventsForMetrics( a ) {

        var i,          
            metric,     //  BAD
            events,
            zones;

        events = {};
        zones = [ "", "warning", "danger" ];

        //  code omitted for clarity
    }

Separate variable initialization from variable declaration

Do not initialize a variable inside the variable declaration. By separating the declaration and the initialization, we provide additional clarity to the code. Also, this provides us the opportunity (if needed) to provide separate comments for both the meaning of the variable (in the declaration) and the default value for the variable (in the initialization).

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    function Position() {

        var widgetHeight,
            headerHeight,
            footerHeight,
            containerHeight;

        widgetHeight = self.context.$widget.innerHeight();  //  GOOD
        headerHeight = self.context.$header.innerHeight();
        footerHeight = self.context.$footer.innerHeight();
        containerHeight = widgetHeight - headerHeight - footerHeight;

        //  if overlaying the footer, don't subtract out its height
        if ( options.overlayFooter ) {
            containerHeight += footerHeight;
        }

        //  set the height of the content to fill the vertical space
        self.context.$container.innerHeight( containerHeight );

        //  if overlaying the footer, set a negative margin on the footer equal to its height,
        //  to pull it back into view
        if ( options.overlayFooter ) {
            self.context.$footer.css( "margin-top", -1 * footerHeight );
        }     
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
    function Position() {

        var widgetHeight = self.context.$widget.innerHeight(),  //  BAD
            headerHeight = self.context.$header.innerHeight(),
            footerHeight = self.context.$footer.innerHeight(),
            containerHeight = widgetHeight - headerHeight - footerHeight;

        //  if overlaying the footer, don't subtract out its height
        if ( options.overlayFooter ) {
            containerHeight += footerHeight;
        }

        //  set the height of the content to fill the vertical space
        self.context.$container.innerHeight( containerHeight );

        //  if overlaying the footer, set a negative margin on the footer equal to its height,
        //  to pull it back into view
        if ( options.overlayFooter ) {
            self.context.$footer.css( "margin-top", -1 * footerHeight );
        }     
    }

Use CamelCase starting with a lowercase letter

When naming a variable, use CamelCase starting with a lowercase letter. Do not use underscores to separate words in a compound name.

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    function Position() {

        var widgetHeight,       //  GOOD
            headerHeight,
            footerHeight,
            containerHeight;

        widgetHeight = self.context.$widget.innerHeight(); 
        headerHeight = self.context.$header.innerHeight();
        footerHeight = self.context.$footer.innerHeight();
        containerHeight = widgetHeight - headerHeight - footerHeight;

        //  if overlaying the footer, don't subtract out its height
        if ( options.overlayFooter ) {
            containerHeight += footerHeight;
        }

        //  set the height of the content to fill the vertical space
        self.context.$container.innerHeight( containerHeight );

        //  if overlaying the footer, set a negative margin on the footer equal to its height,
        //  to pull it back into view
        if ( options.overlayFooter ) {
            self.context.$footer.css( "margin-top", -1 * footerHeight );
        }     
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    function Position() {

        var WidgetHeight,       //  BAD (doesn't start with a lowercase letter)
            headerheight,       //  BAD (doesn't capitalize "height")
            footer_Height,      //  BAD (doesn't omit underscores)
            container_height;   //  BAD (doesn't omit underscores)

        WidgetHeight = self.context.$widget.innerHeight(); 
        headerheight = self.context.$header.innerHeight();
        footer_Height = self.context.$footer.innerHeight();
        container_height = WidgetHeight - headerheight - footer_Height;

        //  if overlaying the footer, don't subtract out its height
        if ( options.overlayFooter ) {
            container_height += footer_Height;
        }

        //  set the height of the content to fill the vertical space
        self.context.$container.innerHeight( container_height );

        //  if overlaying the footer, set a negative margin on the footer equal to its height,
        //  to pull it back into view
        if ( options.overlayFooter ) {
            self.context.$footer.css( "margin-top", -1 * footer_Height );
        }     
    }

"Apps Hungarian" notation is acceptable; "System Hungarian" is not

"Apps Hungarian" notation refers to the practice of embedding the purpose of a variable in its name. This is acceptable. "System Hungarian" notation refers to the practice of embedding the data type of a variable in its name. This is not acceptable.

For example, this is good:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    function Position() {

        var widgetHeight,       //  GOOD
            headerHeight,
            footerHeight,
            containerHeight;

        widgetHeight = self.context.$widget.innerHeight();
        headerHeight = self.context.$header.innerHeight();
        footerHeight = self.context.$footer.innerHeight();
        containerHeight = widgetHeight - headerHeight - footerHeight;

        //  if overlaying the footer, don't subtract out its height
        if ( options.overlayFooter ) {
            containerHeight += footerHeight;
        }

        //  set the height of the content to fill the vertical space
        self.context.$container.innerHeight( containerHeight );

        //  if overlaying the footer, set a negative margin on the footer equal to its height,
        //  to pull it back into view
        if ( options.overlayFooter ) {
            self.context.$footer.css( "margin-top", -1 * footerHeight );
        }     
    }

and this is bad:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    function Position() {

        var nWidgetHeight,       //  BAD
            nHheaderHeight,
            nFooterHeight,
            nContainerHeight;

        nWidgetHeight = self.context.$widget.innerHeight();
        nHheaderHeight = self.context.$header.innerHeight();
        nFooterHeight = self.context.$footer.innerHeight();
        nContainerHeight = nWidgetHeight - nHheaderHeight - nFooterHeight;

        //  if overlaying the footer, don't subtract out its height
        if ( options.overlayFooter ) {
            nContainerHeight += nFooterHeight;
        }

        //  set the height of the content to fill the vertical space
        self.context.$container.innerHeight( nContainerHeight );

        //  if overlaying the footer, set a negative margin on the footer equal to its height,
        //  to pull it back into view
        if ( options.overlayFooter ) {
            self.context.$footer.css( "margin-top", -1 * nFooterHeight );
        }     
    }

Next time

Whitespace conventions.

Source: http://www.finitewisdom.com/people/joshua-...