rTraction

Viewing posts by: Jeremy Richardson

first-child, last-child for menus

November 18, 2008

Written by | No Comments



Menus can be range from simple text to complicated visual effects.  When it comes to the most used and popular menus one of the most common things we do on our sites is add a separator character.

For example:

Home | Products | Contact Us | About Us

CSS seems like it should be the simplest solution. Add a border-left: 1px solid #000. However the first element of this menu should not have this border. CSS 2.1 has given us the first-child and last-child selectors. This would be the perfect solution other than the fact that Internet Explorer 6 does not support these selectors (CSS and browser content and compatibility). IE7 is incrementally better supporting just the first-child selector.

Until we finally can let go of IE6 support (perhaps when IE8 comes out?), we will need to find another solution. The easiest is to add the class “first” to the first element of the menu and “last” to the last element of the menu. This will allow us to target styles specifically for those menu items.

Now that we develop a number of our sites in Drupal, we have had to come up with a solution for it. If developing in Drupal 6 then the work is already done for you. Drupal 6 now includes first and last classes on all menus. Drupal 5 only includes the first and last classes on primary and secondary links and not for menus displayed in blocks.

Using theme overides you can customize your site to add first and last classes. Take a look at the following article on Have “first” and “last” classes on menu blocks.

Fixed cell widths in tables

November 12, 2008

Written by | No Comments



TableWe recently ran into a situation where we needed multiple tables to appear as a single table.  To make sure each column lined up, we needed to set the width of each cell to a set pixel amount.

The first attempt added a width to the <td> as follows:

some content goes here

However, by nature, table cells will always resize to accommodate the content that is placed in them. That is what they were designed to do. The cell will maintain its 150 pixel width as long as the content is smaller than the specified width.

The solution is to add a div inside each cell. It adds some extra markup, but will ensure that the cell will not resize beyond the specified width. Divs can be set to specific dimensions, and will stay as such even if the content will not fit inside.

So our table cell code now becomes:


some content goes here

PHP Optimization

October 24, 2008

Written by | 1 Comment



Every now and then, you run into a situation where you have a large amount of code executing to create a complex page.  This can lead to response times for web page requests that are not adequate for your client. Everyone should know by now that some basic coding standards and some simple caching can go a long way to prevent slow page load times. Sometimes, however, those simple steps are just not enough.  Be sure that pages only load the code they require to display information.  Also, be sure that you have set up some caching on your website (this also helps with heavy traffic loads).  Another thing to remember: to find out where any bottlenecks might be hiding, it is important to run some benchmarks on your code.  Sometimes a simple database call that might be executed multiple times on a page can be running very inefficiently and drastically affecting all of your load times.

One tool that can be useful is XDebug (which we previously talked about here). One thing not covered in our previous blog article is the ability to perform benchmark analysis on data captured with XDebug.  Using a tool called WinCacheGrind, you can analyze the cachegrind profile file output by XDebug. This will allow you to target and eliminate or reduce functions that negatively impact your website’s performance.  If you are hosting your site with Apache, another notable option is to set up Alternative PHP Cache (APC).  You will need to verify all your website’s functionality is working properly with APC enabled.  Our experience is that APC provides a great reduction in load times when configured properly.

Last but not least, be sure to think about performance when writing your code.  There is a great article with 40 optimization tips over at reinholdweber.com.  Click here to check out the optimization tips and feel free to comment with any other performance tools or tips you or your company have found useful.

Sorting 2-dimensional arrays in PHP (multi-dimensional array)

September 10, 2008

Written by | 2 Comments



There have been numerous occasions where we have retrieved the result of an array and yet still needed to do some kind of sorting.  Up until now it seemed like there was no answer.  The answer was found with the function array_multisort.  The names of some PHP functions can be quite misleading but this one does what it says.

The trick to using this function is that it sorts based on columns.  The normal layout of a database table returned into an array is with each row of the table is a seperate element of an array.  The 2nd dimension of the array has the table row names as the keys with the value attached.

Database table turned into array

So there is our table represented in an array with each element as a separate row.  To sort we need an array for each column, in this case fruit and color.  We use the following code to accomplish this.

foreach ($query_result as $key => $row) {
    $fruit[$key]  = $row['fruit'];
    $color[$key] = $row['color'];
}

It seems quite unintuitive but essentially each column is a separate array with the row number being the key. Now we are able to plug this new data into the array_multisort function to sort our existing array (NOTE: the new column based arrays we created are specifically for the purpose of sorting)

array_multisort($color, SORT_DESC, $fruit, SORT_ASC, $query_result);

Basically you list the order of columns you want to search by. In this case we’re sorting by color descending first and then by fruit ascending. The last parameter is the multi-dimensional array that you want to sort.

Seems like a convoluted way of a simple sort. It’s always best to do all sorting and querying in the database but for the few situations that just isn’t possible, we have a solution using array_multisort in PHP.

LightWindow IE6 bug – image size (resizeTo)

September 5, 2008

Written by | 8 Comments



LightWindow is an advanced “lightbox” JavaScript component that can be used for a wide range of media. We were simply trying to use it as an image gallery.  What we ran into is that every once in a while when clicking on a link to trigger the slideshow, LightWindow would fail to size the image properly in IE6.  This only seemed to happen in IE6 though reading through others experiences it seems like it may happen in IE7 as well although we never came across any problems with IE7.

When you run into a problem with someone elses tool it can be very difficult to solve the problem.  After an exhaustive search we were able to find the solution posted on a german blog at www.trilodge.de.  Although we don’t speak german it was obvious this was the solution to our problem.

Although this solution is already available from www.trilodge.de we know this will help any other developers who run into this issue as its hard to find the german solution being the blog is in another language.

The problem happens in the image loader.  It seems to think the image has loaded when it has not.  Therefore it is unable to get an accurate size.

To fix replace:

// We have to do this instead of .onload
this.checkImage[i] = new PeriodicalExecuter(function(i) {
	if (!(typeof $('lightwindow_image_'+i).naturalWidth != "undefined" && $('lightwindow_image_'+i).naturalWidth == 0)) {

		this.checkImage[i].stop();

		var imageHeight = $('lightwindow_image_'+i).getHeight();
		if (imageHeight > this.resizeTo.height) {
			this.resizeTo.height = imageHeight;
		}
		this.resizeTo.width += $('lightwindow_image_'+i).getWidth();
		this.imageCount--;

		$('lightwindow_image_'+i).setStyle({
			height: '100%', width: '100%'
		});

		if (this.imageCount == 0) {
			this._processWindow();
		}
	}

}.bind(this, i), 1);

With this:

// We have to do this instead of .onload
var ie = (document.all)?1:0;
this.checkImage[i] = new PeriodicalExecuter(function(i) {
	if(ie){ //THE BROWSER IS IE
		if ( $('lightwindow_image_'+i).complete && !(typeof $('lightwindow_image_'+i).naturalWidth != "undefined" && $('lightwindow_image_'+i).naturalWidth == 0)) {
			this.checkImage[i].stop();

			var imageHeight = $('lightwindow_image_'+i).getHeight();
			if (imageHeight > this.resizeTo.height) {
				this.resizeTo.height = imageHeight;
			}
			this.resizeTo.width += $('lightwindow_image_'+i).getWidth();
			this.imageCount--;

			$('lightwindow_image_'+i).setStyle({
				height: '100%', width: '100%'
			});

			if (this.imageCount == 0) {
				this._processWindow();
			}
			//alert('IE has been detected')
		}
	}
	else
	{//NOT IE, PROBABLY FF, OPERA, OTHER
		//this line works for all other browsers
		if ($('lightwindow_image_'+i).complete && !(typeof $('lightwindow_image_'+i).naturalWidth != "undefined" && $('lightwindow_image_'+i).naturalWidth == 0)) {

			this.checkImage[i].stop();

			var imageHeight = $('lightwindow_image_'+i).getHeight();
			if (imageHeight > this.resizeTo.height) {
				this.resizeTo.height = imageHeight;
			}
			this.resizeTo.width += $('lightwindow_image_'+i).getWidth();
			this.imageCount--;

			$('lightwindow_image_'+i).setStyle({
				height: '100%', width: '100%'
			});

			if (this.imageCount == 0) {
				this._processWindow();
			}
		}
	}

}.bind(this, i), 1);

If you have any other suggestions or ran into any other problems feel free to post them below and we would be happy to update the post to help others.