Skip navigation

design: Amazon.com product switcher

October 23, 2004 There's a little Amazon.com product switcher on the pages of this site. Each time you visit or refresh a page, a script shows you the next product. Maybe you'd like one too? If so, here's what the pieces look like and how they fit together. Probably more of a coding exercise than a drop-in component, but feel free to scavenge in these scripts for parts.

scripts to include

Each page in the site includes two scripts. Here they are:

<script type="text/javascript" src="core.js"></script>
<script type="text/javascript" src="design.js"></script>

The first script, core.js contains code for reading and writing cookies, style-switching, and displaying the Amazon product links. This code borrows heavily from the original article Alternative Style: Working With Alternate Style Sheets by Paul Sowdon and includes cookie functions originally contributed by JavaScript master Peter-Paul Koch. We'll take a look at all that stuff in a minute.

The second script creates a two dimensional array of product titles, Amazon.com reference numbers and product illustrations that acts as a small client-side database. You might have noticed how there are different sorts of books or music or stuff displayed depending on where you are in this site - this is done by using a different data file in each section. The one for the design area is called design.js. Here's what it looks like:

// books for the design section
var di = new Array();
di[0] = ["Idea Index","1581800460","1581800460.jpg",
         "Brilliantly simple collection of design ideas."];
di[1] = ["User Interface Design for Programmers","1893115941","1893115941.jpg",
         "Light and cheerful enough to read on the bus."];
di[2] = ["Fresh Styles for Web Designers","0735710740","0735710740.jpg",
         "Great, lively work."];
di[3] = ["Defensive Design for the Web","073571410X","073571410X.jpg",
         "Like passenger air bags for your website."];
di[4] = ["Pantone Guide to Communicating With Color","0966638328","0966638328.jpg",
         "Another book I'm wearing out."];
di[5] = ["Don't Make Me Think","0789723107","0789723107.jpg",
         "Sensible, cheerful, funny."];
di[6] = ["The Elements of Color","0471289299","0471289299.jpg",
         "The classic text on color theory."];
di[7] = ["The Design of Sites","020172149X","020172149X.jpg",
         "User interface patterns for the web."];
di[8] = ["Photoshop 7 Artistry","0735712409","0735712409.jpg",
         "Some of this stuff is amazing."];
di[9] = ["The Icon Book","0471599018","0471599018.jpg",
         "Dated, but the only thing out there like it."];

There's a similar data file for the music area called music.js, one for the sites area called sites.js and so on.

what's in the data

The design.js file above creates an array named di. There are 10 items in the array. Each of the individual items is itself an array. You end up with an array of arrays containing four parts in this order:

  1. a book title
  2. the Amazon.com ASIN number
  3. an image filename
  4. a little blurb I wrote about the book

You refer to an individual item using JavaScript array notation, and both the inner and outer arrays begin with item zero. So the code to access the .jpg image file (3rd item in the inner array) for the book "User Interface Design for Programmers" (2nd item in the outer array) looks like this:

di[1][2]

Adding items to the array is straightforward - just create a new item di[10] = ... in the same format as the other items. There are a half dozen or so similar little Amazon.com data files on this site, each with different sorts of stuff in them and with a differently named array. Now you that know what the data looks like, let's take a look at how we work with it.

initialization

The initAmazon function you see below gets called by the window's onload event, this means it happens after the page has rendered in the browser. All the code that follows lives in core.js.

initStyles(); /* fires immediately */

function init() {
  setPersonalityIcon(myPersonality);
  setTextSizeIcon(myFontSize);
  initAmazon();
}
window.onload = init; /* fires after page load */
window.onunload = writeStylePreferences; /* write style prefs on unload */

The initAmazon() function follows. It has some strange syntax, but it's really trying to do three simple things:

  1. Figure out which of the different data files is active on the page.
  2. Read a cookie that contains a single number - this is used to identify an item to show from the data file.
  3. Display the item.

The first thing we do is to declare the undef variable so we have something known to test against. Then, one-by-one, we try each of the arrays from all the different data files to see if one is not undefined. If one of the tests passes, we read the cookie for that data file and then use it as the third argument in the showAmazonItem() call.

/* amazon gimcracks*/
function initAmazon() {
  var undef = "undefined";
  if (typeof oo != undef) {
    var ooIdx = readCookie("oo");
    showAmazonItem(oo, "oo", new Number(ooIdx ? ooIdx : 0)); // home page
  } else if (typeof si != undef) {
    var siIdx = readCookie("si");
    showAmazonItem(si, "si", new Number(siIdx ? siIdx : 0)); // sites
  } else if (typeof di != undef) {
    var diIdx = readCookie("di");
    showAmazonItem(di, "di", new Number(diIdx ? diIdx : 0)); // design
  } else if (typeof fa != undef) {
    var faIdx = readCookie("fa");
    showAmazonItem(fa, "fa", new Number(faIdx ? faIdx : 0)); // family
  } else if (typeof mu != undef) {
    var muIdx = readCookie("mu");
    showAmazonItem(mu, "mu", new Number(muIdx ? muIdx : 0)); // music
  } else if (typeof fl != undef) {
    var flIdx = readCookie("fl");
    showAmazonItem(fl, "fl", new Number(flIdx ? flIdx : 0)); // influential fiction
  }
}

There's one bit of syntax in the above example that might be a bit confusing. The third (numeric) argument to showAmazonItem looks like this: new Number(ooIdx ? ooIdx : 0). What this does is to make sure what we pass to the function is really a Number object, and not something else, like a String. Inside the Number constructor is a trinary operator. You can read it like this: "If the ooIdx variable is not null, use it, otherwise use zero."

showing the item

We've found our array, read our cookie and made the call to showAmazonItem(). What's it do? Here's what it looks like:

function showAmazonItem(amarray, amarrayname, idx) {
  var linkprefix = "http://www.amazon.com/exec/obidos/ASIN/";
  var linksuffix = "/deepgraysea-20";
  var imgprefix = "images/";
  var titlesuffix = " at Amazon.com";
  // preload new image
  var newAPix = new Image();
  newAPix.src = imgprefix + amarray[idx][2]; 

  var alink = document.getElementById("amazonlink"); // image link
  if (alink) {
    alink.href = linkprefix + amarray[idx][1] + linksuffix;
    alink.title = amarray[idx][0] + titlesuffix;
  }
  var atitle = document.getElementById("amazontitle"); // text link
  if (atitle) {
    atitle.href = linkprefix + amarray[idx][1] + linksuffix;
    atitle.title = amarray[idx][0] + titlesuffix;
    atitle.firstChild.nodeValue = amarray[idx][0];
  }
  var ablurb = document.getElementById("amblurb"); // editorial
  if (ablurb && ablurb.firstChild) {
    ablurb.firstChild.nodeValue = amarray[idx][3];
  }
  var apix = document.getElementById("amazonpix"); // image
  if (apix) {
    apix.src = newAPix.src;
    apix.alt = amarray[idx][0] + titlesuffix;
  }

  var nextidx = new Number(idx + 1);
  createCookie(amarrayname, nextidx >= amarray.length ? 0 : nextidx, 365);
}

The first part of the function is pretty straightforward. It initializes some variables we'll use to create the links to items in the Amazon.com website. The /deepgraysea-20 part tells 'em to toss a nickel in my jar whenever someone clicks through from the site and buys an egg beater or something. It makes me wonder if there are 19 other deep gray seas out there. Scary.

Next thing that happens is we get a reference to the anchor tag containing the image. This is an existing element in the XHTML page. We're going to change both the href and the title. Remember way up the page how we saw how to grab one specific item out of the array of design books? We do that here for the href with the amarray[idx][1] statement. The amarray is one of the arguments to our function, idx is another. We get the Amazon.com ASIN number from our data file with this syntax. The title comes from amarray[idx][0]. Then we do the same sort of thing with the thumbnail image.

The visible text you see as the link, and the editorial comment below it, are a bit trickier. If you look at the line that loads the editorial you'll see that first we obtain a reference to the element by its ID. Then we double-check and make sure it's not null and that there's something inside it (a child element). If so, we replace the child element with the editorial text stored in amarray[idx][3].

Finally, we increment the array index argument (or set it to zero) and resave the cookie.

XHTML page code

Here's a typical example of how the Amazon.com item appears on the page. The scripts above replace many of these values dynamically. You'll want to be careful not to have extra spaces in the anchor tags, otherwise the child node business may go awry.

<!-- amazon stuff -->
<div id="amazon">
  <div id="amheader">mental floss</div>
  <div id="ampixdiv"><a 
    id="amazonlink" 
    title="Idea Index at Amazon.com" 
    href="http://www.amazon.com/exec/obidos/ASIN/1581800460/deepgraysea-20"><img 
      id="amazonpix" 
      src="images/1581800460.jpg" 
      alt="Idea Index at Amazon.com" /></a></div>
  <div id="amtitlediv"><a id="amazontitle" 
    title="Idea Index at Amazon.com" 
    href="http://www.amazon.com/exec/obidos/ASIN/1581800460/deepgraysea-20">Idea Index</a></div>
  <div id="amblurb">Brilliantly simple collection of design ideas.</div>
</div>

By coding a static version of an Amazon.com link in the page, we allow visitors without JavaScript enabled to make impulse purchases too. They just don't see all the different items.

CSS styling

You probably noticed that there weren't any visual styling cues in the XHTML code. The whole site's like that, so it can switch between different font sizes and layouts using stylesheets. Here's how the Amazon item appearance and position is specified for the deep gray sea personality on the site, taken from the deepgraysea.css style sheet.

/* shameless amazon marketing */
#amazon {border: 1px dotted #aaa;
  margin: 30px 30px 15px 15px;
  width: 145px;
  vertical-align: middle;
  position: absolute;
  top: 700px;
  right: 35px;
  text-align: center;} 
#amheader {font-weight: bold;
  margin: 10px 15px;}
#ampixdiv {margin: 0 15px;}
#ampixdiv img {margin: auto;
  border: 1px solid #0D2D40;
  z-index: 10;
  display: block;}
#amtitlediv {margin: 2px 15px;}
#amauthdiv {margin: 0 15px;}
#amblurb {margin: 5px 15px 15px 15px;}
      

This particular layout has the Amazon item absolutely positioned 700 pixels down from the top of the page and 35 pixels from the right edge. That's where it fits well even with the text set to the largest size. The rest of the stylesheet code is mostly concerned with margins for indentation and spacing. The font size is chosen by the user independent of the layout, but that's another example.

Egg Beater I hope this example has been interesting and not too confusing. If you liked it, maybe buy an egg beater or something.

D
D