Matt Snider JavaScript Resource

Understanding JavaScript and Frameworks

Saturday, December 29, 2007

Faux Columns

This past week has been really crazy: 3 Christmas celebrations, 1 Birthday, and family staying over for the last 3 days. Consequently, I have not succeeded in a finishing my xJson Object article. So instead of discussing xJson, today we will discuss a simpler, but very useful technique, known as Faux Columns.

The Problem:
If you have ever tried to design a two-column layout without using tables, you should know that the two columns (by default) will not be the same height. This is normally not a problem until you want a line of some kind dividing the columns. This line should be the height of the tallest column. Initially, you might think that adding a border-right to the left column or a border-left to the right column, will do the trick. However, because one column may (and probably will) be larger than the other, borders will not work. The simplest fix is to apply a height to both columns and call it a day. However, many layouts have dynamic content, such as this blog, and you will not be able to specify a height.

The Solution:
There are many different solutions to this problem (including JavaScript, CSS hacks, etc.), but the simplest (and x-browser safest) one is Faux Columns; it requires no hacks, only good HTML and CSS design. Faux Columns were first introduce by A List Apart. Since, the column height can be dynamic, instead of applying a background or border to the columns, you wrap the columns inside an element and apply a background style to that element. That background style will have your column background and border styles. For example, lets assume you use the following HTML:

Example 1: Simple HTML

… <body><div id=”doc”> <div id=”header”>This is my header</div> <div id=”main”> <div id=”sidebar”>Put sidebar elements here</div> <div id=”content”>Put content elements here</div> <div class=”clearfix”></div> </div> <div id=”footer”>This is my footer</div> </div></body> …

And you want to use this HTML to produce a two column layout with a column-independent header and footer:

Example 2: Layout

faux layout example

Then apply the following styles (I recommend using reset.css and base.css as well):

Example 3: Styles

/** Center the doc div; excluding IE, see IEHacks for more info on how to do this in IE < 6 */ #doc { margin: 0.5em auto; overflow: hidden; width: 90em; } /** Replace these with whatever styles you prefer */ #header { border-bottom: 1px solid #830A04; height: 3.6em; } /** Creates the faux column */ #main { background: #EFEFEF url(../images/bg/column.gif) 25em 10px repeat-y; /** faux column graphic */ clear: both; } /** Right column */ #content { float: right; width: 64em; } /** Left column */ #sidebar { float: left; width: 24em; } /** Replace these with whatever styles you prefer */ #footer { background-color: #FFF; border-top: solid 1px #000; clear: both; padding-top: 1em; } /* (en) clearfix method for clearing floats */ .clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } /* (en) essential for Safari browser !! */ .clearfix { display: block; }

I prefer my designs to be 100% elastic so that they are accessible and have used ems to specific widths. However, you could just as easily use pixels and a fixed layout. If you use the ‘reset.css’ and ‘base.css’ then 1em = 10pixels. In this example, the background image is a solid color with the column divider graphic on the left side, and the sidebar color is specified by the background style of main. This way, I simply offset the background image to the width of the sidebar, and it scales to all font-sizes. The only constraint on the background image is that it needs to repeat vertically, otherwise, you will not get the column effect (so you need to create a repeating vertical pattern).

If you use a fixed layout and want a less plain sidebar design, then do not offset the image. Instead offset the column divider in your graphic to the width of the sidebar (or wherever you need the gutter).

You might be wondering why the empty div with class ‘clearfix’ is there. This is needed because the ‘main’ div’s height will not reflect the height of the content floating inside it. The ‘clearfix’ div forces an empty div to be placed at the end of the columns that clears both the left and right float. This non-floating element, is positioned after the tallest floating content and causes the ‘main’ div to then expand to the height of the largest column.

Here is a simple example that uses a double vertical line to divide the columns.

posted by Matt Snider at 3:43 pm  

Tuesday, December 18, 2007

Semantic HTML for a Simple 5-Star Rating System

I am going to deviate this week from the Json Object discussion, as I have not had any time to work on it. Instead, I wanted to share a technique you can use to write semantic HTML for a rating system. If you have ever used a site like Amazon.com or Yelp.com, then you are familiar with the star rating system (0 stars = worst rating, 5 stars = best rating). However, most rating systems do not do a good job when browser font-size or zoom changes, making them inaccessible. Also, most tend to use a different graphic for each rating, requiring up to 10 graphics to load. The technique I worked on this week, not only scales well, but only requires 2 graphics, and you can change the color of your ratings with simple CSS.

Step 1: Create 2 Images

First decide which size you want the image to normally be (for me this was 80px wide by 16px high); this is a 1 to 5 ratio, because I am going to use a 5 point rating system, which will play an important role for the size of each rating point symbol. Use a program like Photoshop to create an image with these dimensions and a transparent background. In a separate window create an 16 x 16 (or 1/5 of the default width you chose) transparent image and draw in the symbol you want to use for the rating point (I used black for the color of my symbol, but it is up to you). I used a star, but it doesn’t matter what you choose so long as the center is transparent and the symbol fills the dimensions. All spaces outside the symbol should be the background color of your page (this is white for my example page). Here is an example of my star:

Example 1: Star Graphics

Single star graphic

Single star graphic

The first graphic shows what “star.gif” looks like by default. The second show, the difference when a background color is applied. I choose red, but you can change it to whatever hex you prefer.

Next copy your 16×16 symbol image 5 times into the original image you created. You should have something that looks like the following:

Example 2: Rating Graphics

5 star graphic

5 star graphic

Example 2 is the first image we will need. I made the background yellow to show how easy it is to change. The second image we need is a background masking image used to cover the part of the rating inverse (if the rating is 1.5, then this will cover the other 3.5 of the symbols). The background should be the color of the site background (white for me), and the left-most pixels should all be the color of the symbols (black for me). This image should be taller and wider than the rating image, because it will need to scale as the browser does. I usually do 2x the original dimensions, which supports up to a +4 font-size. Therefore, the dimensions of my “ratingbg.gif” is 160×32px:

Example 3: Rating Background Graphics

5 star graphic

The gray border is only here to show contrast so you can see what the image looks like. The small sliver of black on the left will be the line that marks the rating position inside of the symbols. This completes all the images and HTML you will need to get the rating system to work.

Step 2: Create Styles to Control the Ratings

Next we style the image tag to support our ratings. I suggest using classes, here are the styles I used:

Example 4: Rating Styles

img.rating { background: #FC0 url(/assets/img/bg/ratingbg.gif) 5em 0 no-repeat; /* specify your color; 5 em is the 5:1 ratio; and the url is wherever the ratingbg.gif is located */ font-size: 1.6em; /* this is the height of a single symbol; mine is 16px */ height: 1em; /* this will cause the image to scale as the font-size changes, default is 16px */ width: 5em; /* this the 5 to 1 ratio that I mentioned, but could be different if your symbols aren’t symetric */ } /* higher specificity than img.rating */ html body img.r9 { background-position: 4.5em 0; } html body img.r8 { background-position: 4.0em 0; } html body img.r7 { background-position: 3.5em 0; } html body img.r6 { background-position: 3.0em 0; } html body img.r5 { background-position: 2.5em 0; } html body img.r4 { background-position: 2.0em 0; } html body img.r3 { background-position: 1.5em 0; } html body img.r2 { background-position: 1.0em 0; } html body img.r1 { background-position: 0.5em 0; } html body img.r0 { background-position: 0 0; }

Step 3: Tie it all Together

Here is a rating of 2.5 in yellow, 1 in blue, and 4.5 in green:

Example 5: 3 Star Rating Variations

2.5 in yellow rating example
1 in blue rating example
4.5 in green rating example

The image heights in this article are slightly off by a fraction, due to rounding issues with other styles inherited in this wordpress theme. I have also created a test page so you can play with the uncorrupted styles and view them in different browsers. Try to scale the font-size and see how nicely the images scale and the rating stays in the appropriate place.

posted by Matt Snider at 3:45 pm  

Wednesday, December 12, 2007

Issues With JsonArray

My goal today was to finish most of the models that I have been working on and share this with you. However, it is turning out to be a much more complicated problem than I originally thought. I want the JsonArray object to dynamically create JsonObjects (as necessary) when retrieving elements out of the array. However, the JsonObject declaration requires that you know what Object is being passed, and more importantly, what keys to expect.

For example, here is what I have for JsonArray:

Example 1: JsonArray

/** * The JsonArray class manages … * * @namespace Mint.Model * @class JsonArray * @dependencies library */ Mint.Model.JsonArray = function(data) { this.update(data); }; Mint.Model.JsonArray.prototype = { update: function(data) { var that = []; this.get = function(i) { if (! that[i]) { var o = data[i]; if (isArray(o)) { that[i] = new Mint.Model.JsonArray(o); } else if (isObject(o)) { that[i] = new Mint.Model.JsonObject(o); } else { that[i] = o; } } return that[i]; }; } });

This will work just fine if all values of the array are non-object. However, if it is an Object (most likely, it is), then the JsonObject method is instantiated. The JKEYS array will be empty, because you haven’t defined it yet and will throw errors. This has been a real thorn in my side and I have not found a good solution around the issue, except possibly in xJson.

I was planning on playing with xJson separately, but since xJson defines the keys in the JsonArray definition, you can leverage them during the JsonObject instantiation. Also, this has the added benefit of being server driven, without requiring client-side awareness and could make these model objects a little more tamper resistant. I will look into xJson this week and post about it on Friday.

posted by Matt Snider at 3:03 am  

Friday, December 7, 2007

JsonObject Model Prototype

I have been doing a lot of server-side work in PHP and JAVA this past month. One of the design practices used by server-side webapp languages is the MVC (model-view-controller) framework. An MVC makes writing extensible and scalable code, much easier. In JavaScript I have seen a couple of attempts at a similar MVC framework, but most of the time it is overkill or poorly implemented. Shutterfly.com on the other-hand, has a lot of JavaScript and a fairly solid MVC implementation.

I have been toying with JavaScript MVC concepts all week and want to share what I developed to improve working with JSON objects. Keep in mind this is a work in progress and I am open to any suggestions:

Example 1: Sample Code

/** * The JsonObject class manages … * * @namespace Core.Model * @class JsonObject * @dependencies core */ Core.Model.JsonObject = function(data) { this.update(data); }; Core.Model.JsonObject.prototype = { JKEYS: [], MODEL: ‘JsonObject’, update: function(data) { var obj = {}, that = this, i = 0; // iterate through the JSON object keys for (var key in data) { var o = data[key]; if (! isType(o, ‘function’)) { // this key is not in the model if (-1 < that.JKEYS.indexOf(key)) { throw('Invalid key (' + key + ') passed into ' + that.MODEL); } obj[key] = o; that[isType(o, 'boolean')? key: 'get' + ckey] = function() {return obj[key];}; that['set' + ckey] = function(o) {return obj[key] = o;}; i += 1; } }; // the keys in the object do not match the keys in the model if (i != JKEYS.length) { throw('Invalid number of keys passed into ' + that.MODEL); } } });

This method takes a JSON object and applies getter/setter methods to that object. Each time update is called, it validates against JSKEYS, which should be an array of the expected keys. We also remove any functions that might have been attached to the ‘data’ object. You may also note that I have a special check for boolean values that does not attach the ‘get’ preface to the getter method. This is because I always preface boolean values with ‘is’ or ‘has’ (or something like that), and I want that preserved in the Function attached to the JsonObject.

Here is an example of how you might use it:

Example 2: Using JsonObject

// a JSON object, most likely returned from the server, representing a car var carJson = { make: ‘ford’, model: ‘contour’, year: ‘1996′, price: ‘$2,000′, isNew: false }; // use the extend (Object Extension) method to create a CarObject, with the appropriate JKEYS set Core.extend(Core.Model.CarObject, Core.Model.JsonObject, { JKEYS: [’make’, ‘model’, ‘year’ , ‘price’], MODEL: ‘CarObject’ }); var car = new Core.Model.CarObject(carJson);

Example 2 will create a CarObject (extended JsonObject), with the following members:

Example 3: CarObject Structure

CarObject = { // constants defined by the prototype object JKEYS: [’make’, ‘model’, ‘year’ , ‘price’], MODEL: ‘CarObject’, getMake(), setMake(), getModel(), setModel(), getYear(), setYear(), getPrice(), setPrice(), isNew(), setIsNew() }

I find it much easier to work with the JsonObjects once the getters and setters have been created, because you have defined what should be there. Plus, with the validation you can be sure that you received the correct JSON Object. Some possible improvements would be to support nested JsonObjects and JsonArrays, and setter type validation (although, this might be overkill).

There are really only 3 types of models that you might need to use in JavaScript: JSON Objects/Arrays, Query strings, and XML. Creating the Models is a good first step in building an MVC as you will need to pass these between the controller and the view, to update the view and send messages to the server. Next week, I will look into these other model types and improve this one a bit.

posted by Matt Snider at 3:35 pm  

Wednesday, December 5, 2007

News: YUI 2.4, ExtJs 2, and RSH 0.6

No article for Tuesday this week. However, there has been some big news in the JavaScript community:

YUI has added a CSS selector utility, Flash graphing, plus a whole lot more.

ExtJs has improved their already impressive client-side application management system, with additional desktop-like features.

Really Simple History now supports Safari, uses the Module Pattern, and many other additional improvements.

posted by Matt Snider at 10:10 am  

Saturday, December 1, 2007

Object Extension

Object extension is one of the most important aspects of an OOP language. Many people believe that a prototype based OOP languages, such as JavaScript, are unable to support this classical OOP feature. Frankly, these people are wrong, and most likely have never studied a prototype based OOP. There are, in fact, two ways (if you know of more, please let me know) of extending objects in JavaScript: Member Copy and Prototype Clone.

Member Copying

This is a brute force technique and the most common method used for extending Objects. Most frameworks started using this technique, see jQuery (<= v1.2) and prototype (<=1.5) extend methods. In this technique you iterate through each member in Object A and add it to Object B. Often Object B is created when the extend Function is executed. Here is an example snippet from jQuery 1.2 extend:

Example 1: Memeber Copy as Implemented By jQuery 1.2

jQuery.extend = jQuery.fn.extend = function() { // copy reference to target object var target = arguments[0] || {}, a = 1, al = arguments.length, deep = false; // Handle a deep copy situation if ( target.constructor == Boolean ) { deep = target; target = arguments[1] || {}; } // extend jQuery itself if only one argument is passed if ( al == 1 ) { target = this; a = 0; } var prop; for ( ; a < al; a++ ) // Only deal with non-null/undefined values if ( (prop = arguments[a]) != null ) // ACTUAL COPY BEGINS HERE // Extend the base object for ( var i in prop ) { // Prevent never-ending loop if ( target == prop[i] ) continue; // Recurse if we’re merging object values if ( deep && typeof prop[i] == ‘object’ && target[i] ) jQuery.extend( target[i], prop[i] ); // Don’t bring in undefined values else if ( prop[i] != undefined ) target[i] = prop[i]; } // ACTUAL COPY ENDS HERE // Return the modified object return target; };

There is a lot going on here, because jQuery allows for deep copy (recursively copying members of the extension objects) and the simultaneous extension of multiple objects. My all-caps “ACTUAL COPY …” comments wrap the actual copy code. The “for in” statement iterates through the extension Object (prop[i]) and applies it to the extending Object (target[i]).

The benefits of the Member Copy method are that it is easily understood and makes multiple inheritance trivial. The negatives are that it is much slower than the Prototype Clone method, it is easy to accidentally override methods, and a bit of hackery is needed to do a deep extension of an Object.

It is slower because you have to iterate through every member of the extension Object and then apply each of those members to the extending Object. In the Prototype Clone method, this can be done in 3 lines of non-looping code. Accidentally overriding methods is a problem, because you might be extending Object A, which has a method ‘toString’ with Object B, which also has a method ‘toString’. However, you wanted to keep the ‘toString’ method of Object A. The Prototype Clone method only allows for single inheritance, which prevents such pit-falls.

Prototype Clone

This is my favored technique as performance is the most important aspect of my applications. The user should never have to wait for your JavaScript to execute and this method can be much faster than the Member Copy method as the operation cost is a constant time operation versus an O(n) operation. Here is an example of the Prototype Clone method from YUI:

Example 2: Prototype Clone as Implemented By YUI 2.3

/** * Utility to set up the prototype, constructor and superclass properties to * support an inheritance strategy that can chain constructors and methods. * Static members will not be inherited. * * @method extend * @static * @param {Function} subc the object to modify * @param {Function} superc the object to inherit * @param {Object} overrides additional properties/methods to add to the * subclass prototype. These will override the * matching items obtained from the superclass * if present. */ extend: function(subc, superc, overrides) { if (! superc || ! subc) { throw new Error(”YAHOO.lang.extend failed, please check that ” + “all dependencies are included.”); } var F = function() {}; F.prototype = superc.prototype; subc.prototype = new F(); subc.prototype.constructor = subc; subc.superclass = superc.prototype; if (superc.prototype.constructor == Object.prototype.constructor) { superc.prototype.constructor = superc; } if (overrides) { for (var i in overrides) { subc.prototype[i] = overrides[i]; } YAHOO.lang._IEEnumFix(subc.prototype, overrides); } },

In this method you first create an anonymous Function ‘F’ and copy the prototype of the superclass to that Function (this prevents changes to the subclass from affecting the superclass). Then instantiate ‘F’ assigning it to the prototype of the subclass. This creates memory pointers on the subclass’ prototype Object to the members attached to the prototype of the superclass. Now when you instantiate the subclass Object, it will have all members of the superclass. It is important to note that you should not be extending an Object that already has values on its prototype, but instead you should use this technique when you first create the subclass Object.

YUI also adds some additional Object pointers (constructor and superclass), which make these Objects behave more like a Classical OOP language. I disagree with this action, because you can extend the Object object, and this method will modify the prototype of Object and break future “for in” statements on all Object objects. They use these methods in detecting Object types and the inheritance model, but I have not yet been convinced of the need for this.

I do like how they allow you to pass in overrides. This is an Object whose members are applied to the subclass after the extension occurs. This allows you to extend and initialize the subclass in one statement.

I suggest a simpler function (which I use in my projects), as follows:

Example 3: Simple Prototype Clone

Core.extend = function(subc, superc, overrides) { if (! superc || ! subc) { throw new Error(”Core.extend failed, please check that all dependencies are included.”); } var F = function() {}; F.prototype = superc.prototype; subc.prototype = new F(); if (overrides) { for (var i in overrides) { subc.prototype[i] = overrides[i]; } } };

And here is an example of how you might use the extend Function:

Example 4: Using Extend

var Item= {}; var Book = {}; Core.extend(Item, Object, { toString: function() { var sb = []; for (var i in this) { if (typeof this[i] !== ‘function’) { sb.push(’&'); sb.push(i); sb.push(’='); sb.push(this[i]); } return sb.join(”); } }); Core.extend(Book, Item, { getTitle: function() { return this.title; }, setTitle: function(s) { this.title = s; } });

If you really need to know the inheritance chain, then I suggest attaching a stack to each new Object that contains the inheritance chain. That way you won’t break ‘for in’ operations of the Object object.

…………………………
Edited: March 15, 2008

I eventually, found a good use for referencing super class, and here is how I modified this method to support it:

Improving Extend With Super

posted by Matt Snider at 3:18 pm  

Powered by WordPress