Like t-shirts? Find hundreds of cool Geek T-shirts at Teenormous

I have previously mentioned using the ruby plugin MiniMagick to resize images. However, I recently realized there is a much easier way that only requires ImageMagick and would therefore work for any web development environment including PHP, Ruby, ASP etc. This technique was inspired by the MiniMagick plugin and involves shelling out directly to the ImageMagick command-line utilities.

I will cover two common techniques:

  • resizing an image
  • determining an image’s width and height

Resizing An Image

To resize an image, you can use ImageMagick’s mogrify utility. For example, to resize an image to 100×100 you would type:

mogrify -thumbnail "100x100>" someimage.gif

The > symbol will make mogrify maintain the aspect ratio. To run this command from RubyOnRails, you can just use backticks to execute it from a command shell like so:

`mogrify -thumbnail "100x100>" someimage.gif`

Determining Image Width and Height

To determine the width and height of the image, we can use ImageMagick’s identify utility like so:

identify -format "%w %h" someimage.gif

This will return the width and height separated by a space. So, to parse these from Ruby you could do:

w, h = `identify -format "%w %h" someimage.gif`.split

It’s that easy. One other side benefit is by running this process from the command-line your webapp will not consume the additional memory needed for the resizing. The command shell will allocate and free this memory. For a RubyOnRails application, this is a huge benefit as one of the biggest issues with other techniques such as RMagick is that they typically may consume too much memory and will crash your web application.

It has been rather quiet around here as I have been rather busy lately trying to get the next release of the GiftHat.com out the door.

In the meantime, here is a simple technique I like to use to focus a form on a web page using Prototype’s built in Events:

The solution

For those of you who just want to dive right in, here is the solution:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <script src="/javascripts/prototype.js" type="text/javascript"></script>
</head>
<body>

    <script type="text/javascript">
//<![CDATA[
Event.observe(window, 'load', function() {$('focus').focus()}, false);
//]]>
</script>
<form action="/login" method="post" name="loginForm">
  <label for="username">Username</label><br/>
  <input id="focus" name="user[username]" size="30" tabindex="1" type="text" />
  <label for="username">Username</label><br/>
  <input name="user[password]" size="30" tabindex="1" type="password" />
  <input name="commit" tabindex="3" type="submit" value="Submit" />
</form>
</body>

</html>

The explaination

This line requires the prototype library:

<script src="/javascripts/prototype.js" type="text/javascript"></script>

The Event.observe javascript is where the magic happens:

<script type="text/javascript">
//<![CDATA[
Event.observe(window, 'load', function() {$('focus').focus()}, false);
//]]>
</script>

This will setup an event that will cause our dynamic function to be called when the window loads. This function will lookup an element that has an ID called focus and call its focus() method.
In case you are wondering what the CDATA part is for, that will just make sure this webpage still validates.

The last part of this is to create an element that has an ID of focus which will get the browser focus after the window loads. In the example above, it is this form element that gets the focus:

<input id="focus" name="user[username]" size="30" tabindex="1" type="text" />

You can definitely do a lot more interesting things with Prototype events than this example, but this should help get the ball rolling.

Before I dive into what that title means, a little background:

To provide full-text searching of gifts within the GiftHat.com, I am using a ruby gem called Ferret written by Dave Balmain.

Ferret is a port of the popular Java search engine called Lucene.

The Ferret library is excellent, but one thing it suffers from is poor Windows support due in large part to the lack of good support for Windows by ruby itself.

But it looks like that is about to change thanks to a new Apache project called Lucy. Lucy will be a direct port of the Java Lucene engine in pure C. This will provide a much more straight-forward way to integrate the Lucene searching functionality into non-Java languages such as ruby, perl, PHP and python.

This is excellent news thanks to Dave Balmain and Marvin Humphrey for making this happen.

For further reading on this news, read it straight from the source here

Like t-shirts? Find hundreds of cool Geek T-shirts at Teenormous

If you need to force images to fit within your web page layout you really only have two options:

  • Resize images on the server.
  • Resize images on the client.

Resize images on the server

If you have the resources, resizing on the server is probably the best solution depending on your requirements. This solution requires server-side software to manipulate the images and store the altered image for future reference. For Ruby, the RMagick library does an excellent job with this. However, manipulating images on the server is a very expensive operation. If you are on a shared server, like I am, this may not be an option for you. But don’t worry, there is an alternative below.

Resize images on the client

The other option for resizing images involves using Javascript on the client-side to resize them on the fly. This solution has two drawbacks:

  • It requires Javascript.
  • It requires downloading the full image, whereas the server-side resizing will result in much smaller image sizes.

If these two drawbacks are ok with you, then read on :)

To resize the images, you need to first create a javascript function to do the resizing. Feel free to use this one that I wrote:

function resize(which, max) {
  var elem = document.getElementById(which);
  if (elem == undefined || elem == null) return false;
  if (max == undefined) max = 100;
  if (elem.width > elem.height) {
    if (elem.width > max) elem.width = max;
  } else {
    if (elem.height > max) elem.height = max;
  }
}

This function has been tested successfully against IE 6 and Firefox 1.5 (if you can verify this against others, please let me know and I will update this list). One thing worth mentioning is that only the longest side of the image needs to be resized to fit your maximum size. The aspect ratio will still be maintained by the web browser.

The resize function expects an image id and an optional maximum size. For this to work properly, the resizing must only occur after the image was loaded. This can be enforced by using the onload attribute of the image tag.

So, in pure HTML, this could be called like so:

<img id="some_image" onload="resize('some_image')" src="some_image.jpg" />

And in Ruby on Rails, this would look like:

<%= image_tag('some_image.jpg', {:id => “some_image”, :onload => “resize(’some_image’)”}) %>

Enjoy!

Javascript Windows

May 24th, 2006

I just ran across this interesting implementation of Javascript windows:

http://blogus.xilinus.com/pages/javawin

They were written using the Prototype javascript library. They are so slick looking I am tempted to find a use for them in one of my side projects real soon.

Creating Bookmarklets

May 18th, 2006

Bookmarklets allow you to add some advanced functionality into a web browser bookmark using just standard Javascript. Many sites, such as del.icio.us are using them to allow users to post information about pages they are viewing back to the site. The Gift Hat Bookmarklet does the same sort of thing by allowing users to post back gifts to their Gift Hat while they are browsing the web.

Today, I am going to walk you through the technique of creating a bookmarklet so you can provide this great functionality to your users.

There are really two parts to a well-designed bookmarklet:

  1. The bookmark
  2. The bookmarklet.

The bookmark

The bookmark is the part that the user will actually add as either their favorite or bookmark within their browser. The only purpose of this piece is to dynamically load the bookmarklet into the currently viewed webpage. So let’s dive right into the code:

var x = document.getElementsByTagName('head').item(0);
var o = document.createElement('script');
if (typeof o != 'object') o = document.standardCreateElement('script');
o.setAttribute('src', 'http://gifthat.com/javascripts/bookmarklet.js');
o.setAttribute('type','text/javascript');
x.appendChild(o);

This code will basically just insert a new javascript tag into the header of the current page and set the src of that javascript to the bookmarklet.js we specified. You will of course want to replace the http://gifthat.com/javascripts/bookmarklet.js with a link to your bookmarklet.

To make this bookmarkable, we need to make a few more changes to the code above:

  • remove all line feeds
  • add javascript: to the front of it
  • add void(0); to the end of it to prevent it from displaying the result of the x.appendChild(o) statement;

The end result is this (NOTE: I added newlines to make it more readable but this should all be on one line):

javascript:var x = document.getElementsByTagName('head').item(0);
var o = document.createElement('script');
if (typeof o != 'object')
  o = document.standardCreateElement('script');
o.setAttribute('src', 'http://localhost:3000/javascripts/bookmarklet.js');
o.setAttribute('type','text/javascript');
x.appendChild(o);
void(0);

Just add that line in as a bookmark in your browser and you should be all set with your bookmark.

The bookmarklet

The bookmarklet is the portion that will be dynamically inserted and executed within the page the user is currently browsing. By keeping this code in a remote javascript file, you have the added benefit of easily upgrading all of your users to whatever bookmarklet changes you make in the future. You could in theory skip this step and just stick everything in the bookmark, but that would not be nearly as flexible.

To create your bookmarklet, you just need to create a javascript file somewhere on a publicly viewable webserver. I put mine in http://gifthat.com/javascripts/bookmarklet.js (Note: this will be up once I release the next version of the Gift Hat).

Then you can just put your Javascript code into your bookmarklet and it will be executed as if it were always a part of the page the user is browsing. One of the more common types of bookmarklets are as follows:

location.href='http://gifthat.com/gift/post?url=' +
encodeURIComponent(location.href) + '&name=' + encodeURIComponent(document.title)

This will redirect the browser to a page and pass along the current webpage’s URL and title.

There are almost limitless possibilities of what you can do in a bookmarklet.

Happy Bookmarkleting!

References: Much of the bookmarklet code was adapted from this post

Custom CSS For IE

May 12th, 2006

I have tried my best to avoid needing to have a custom IE css file. This has involved many painful hours over the past few years of finding creative ways to write my HTML and CSS in just the right way to ensure that every browser is happy.

However, I have finally thrown in the towel on one particular annoyance I am having where my tabs are 1-2 pixels off in IE on a new layout I am working on for the GiftHat.

Thankfully, a post on the IE blog pointed me towards a method that doesn’t involve hacking the CSS in ways that are guaranteed to break in future IE versions. You can just add a simple line into your HTML file like so:

<!--[if IE]>
  <link href="ie-fix.css" media="all" rel="Stylesheet" type="text/css" />
  <![endif]-->

Then only IE will include this CSS file.

For futher reading, I also found this great article on the subject:
http://www.positioniseverything.net/articles/ie7-dehacker.html

Prototype Visual Reference

April 28th, 2006

I just ran across this great visual diagram of the prototype javascript library:

http://www.snook.ca/archives/prototype.png

It was put together by Jonathan Snook and is a great cheat sheet if you are working with the prototype library.

There are a ton of great plugins for Firefox that make Web development a whole lot better. I really don’t know how I managed without them.

My most recent addition is called FireBug, which provides a number of great features including:

  • Javascript and CSS error notification.
  • Inspection tools for HTML, the DOM, CSS and events.
  • A Javascript command line.
  • XmlHttpRequest spying (which is great for AJAX debugging).

Some of my other favorite Firefox web development extensions include:

  • Web Developer – This should be in every web developer’s tool box. It provides a ton of different utilities for doing things such as disabling cookies and javascript, informational tools such as highlighting elements within your page, tools for validating your HTML and CSS, and way too much more to list.
  • DevBoi – A one stop shop for all of your reference documentation needs. It includes the docs for HTML, CSS, DOM, Javascript and also has add on packs for Ruby On Rails, PHP and XUL. Be sure to install the offline version if you want to be able to access these without internet access.
  • IETab – This is a great tool for viewing your page in IE from within Firefox. It will open the page in a new tab that is rendered using the IE engine. Pretty slick.

If you have any that you think I missed, I would love to hear about them.

Beware the Googlebot

April 8th, 2006

So, I noticed I was receiving a random error from the Gift Hat by one of my ajax auto complete forms.

An ajax submit was occurring without any data, which is impossible from within a browser since a user has to enter data for the ajax form to submit.

Here is the Ajax code in question:

new Ajax.Autocompleter('find_hat', 'find_hat_auto_complete', '/hat/auto_complete_for_find_hat', {indicator:'indicator'})

Thanks to my Exception Notifier setup, I was receiving very detailed emails when the error occurred including this interesting tidbit:

HTTP_FROM : googlebot(at)googlebot.com

It turns out, the googlebot traverses your Ajax code, so beware of the Googlebot or any other random non-human agents. They may be doing things that would otherwise be impossible so plan for these cases as well when building your web apps.