Post Page-Loading iPad/iPhone/iPod CSS Styles, But Only When Needed

March 29, 2012

(For the purposes of this article I will only refer to the iPad, however, I am speaking in terms of any i-Product: the iPad, the iPhone, or touch iPod.)

Recently, I designed a large website that needed to work on all the basic desktop browsers (IE 7/8/9, Safari, Firefox, Chrome). Everything went great until I was done with the site. As soon as I was done, I was told that it now needed to support the iPad. This was not a big deal but was a little problematic since I had not initially designed the site for viewing on those devices. However, the site was all standard CSS, HTML, and JavaScript so I knew it would not be a major task to add in support.

The Problem with iPad
Right away, I ran into a few problems. The first problem was the fact that the iPad relies on the onclick() method being attached to an element in order to determine if it should pass synthesized mouse events to it or not. I solved this with a pretty simple method, and I have written an article that explains my solution in-depth, here. For now, the subject of this article deals only with the iPad’s default CSS settings. Mainly, the fact that scrollbars are turned OFF by default on these devices and how to easily turn them back on, but only when the user is viewing your site with an iPad. “Aha!”, you say… why can’t we just add these CSS changes to our main site’s CSS definitions? Because Safari on the desktop and iPad use the same Webkit CSS package. Which means that if you want to customize your CSS look for each of these versions of Safari, you will need to determine on-the-fly which device is looking at your site and make any CSS additions needed (or not). Also, because of future updates to other browsers, we want to make sure that we do not inadvertently affect these other browsers by assigning styles we do not need.

You see, when the iPad user interface was designed, it was decided that scroll bars were a thing of the past and should be turned OFF by default. Touch commands are the new darling of the user interface community, but since not every device is touch-event driven, this can cause problems for web designers. Ideally, you want to have as few versions of a website as possible. Ideally, you strive for a single, perfect website. One that looks great on all devices. But realistically, this never happens since a website that looks awesome on one device rarely looks good enough on all the others… so, for now, you usually end up creating two websites – one for desktops/tablets, and one for mobile phones.

Bye-Bye Scrollbars
Now, a lack of scrollbars is normally not a problem on the iPad, especially for sites designed specifically for viewing on these devices. But there have been many times I have designed sites which contain smaller, scrollable regions on their pages which do not visually look scrollable when viewed on an iProduct. Since our overall goal as great designers is to always strive for creating intuitive content, this lack of scrollbars can actually work against us by bringing down our site’s overall initial intuitiveness and usability.

Maybe scrollbars are a thing of the past, but for now, users will still need them in order to help them make the move across the gap from traditional to touch-based user interfaces. Sure, most iPad users are aware that you can drag elements and they will scroll if they are able to scroll. But, what gets overlooked is that sometimes elements which DO contain scrollable content don’t look like they are scrollable, so users will not even try. They have no scrollbars acting as a visual cue to let users know they can scroll this item’s content, so a lot of visitors (who may be paralyzed by the fear of clicking the wrong thing) won’t explore your page and so miss important content. So, what to do? Well, add scroll-bars! But how do we do that for just the iPad?

What I needed was a solution that was not a plug-in, or some browser-based hack. It had to be robust. It couldn’t be brittle and break after the first update to any of the site’s supported browsers. You see, in these days of constant software updates, many browsers now update themselves without requiring the user to actively seek updates, download them, then install them manually.

This is great for keeping your browser current, but it also means that every time a browser is updated, any non-standard, remotely-fragile solutions that you have hacked together to make your site function, have now become time bombs. You never know which update to which browser will cause them to halt your site’s functioning. So, any web design solutions you implement need to be simple, based on standard web technologies, and robust without depending on a specific browser version to work properly.

Apple’s Webkit
Apple has a great web browser resource called the WebKit Open Resource Project which is:

WebKit is an open source web browser engine. WebKit is also the name of the Mac OS X system framework version of the engine that’s used by Safari, Dashboard, Mail, and many other OS X applications. WebKit’s HTML and JavaScript code began as a branch of the KHTML and KJS libraries from KDE…

It does a great job by default on most items. However, if your page really needs to have those small, indicating scrollbars, then you need to turn them on yourself using webkit without affecting the rendering of your page in other, desktop browsers, like Safari. If you are not careful, you will end up with tiny scrollbars in the desktop version of Safari as well as the iPad version. Why? Because they both rely on Webkit! So, if you don’t filter the userAgent to look for just the iPad info, then you inadvertently end up assigning the styles to both.

The Solution
So, how do you adapt your site to the iPad without requiring you to add a lot of extra code and style sheets to your website? Part of the answer is to use some JavaScript to do some post-load page manipulation in order to augment any elements that require special attention for them to function properly on the iPad (see my Article “Make Your jQuery Website Buttons/Links Work with iPad/iPhone”). The other half of the solution is to load some additional CSS styles, but only if the site is loaded onto an iPad.

You may be thinking right now,”Why not just use jQuery?”… well, the problem with that solution is that the additional CSS stylesheet really needs to be loaded in the HEAD tag of your HTML page, which means that this must be done BEFORE your jQuery even gets loaded. Also, if you try to simply re-write the page’s HEAD tag after load and after jQuery runs, you get unpredictable results in some browsers. So, the best solution is one that does not rely on any other API than the standard library of default JavaScript functions.

Below is the portion of the code where the magic happens. It is standard JavaScript and does not use jQuery since it has to happen in the head tag, before any jQuery is loaded and just after our site’s base CSS external definitions are loaded. To download the complete source and example files click here.

// we use a regular expression to see if the user agent string contains iProduct identifiers...
if( String(navigator.userAgent).search(/(ipad)|(iphone)|(ipod)/i) > 0 )
{
// we then dynamically add in an additional stylesheet definition.
// this must load AFTER your site's normal CSS definitions, or they might be overwritten
document.write('<link rel="stylesheet" type="text/css" href="scripts/website_styles_iproducts.css">');
}

To view the above code in action, load this page onto your iProduct then click here. You will not see any effect on any other non-iProduct browsers.

Last Note
You can use the above method to look for any particular browser or mobile device if you know it’s user agent identifier. Here is a good article to get you started on identifying other devices.

Just be sure that the over code appears INSIDE the head tag of your HTML page and AFTER the other link tags that you have loading your site’s main CSS definitions.


The problems with toFixed() in JavaScript

July 14, 2011

This tutorial requires an intermediate understanding of JavaScript, HTML, and CSS.

So, what’s wrong with toFixed()?
I do e-commerce websites and often I need to calculate cost amounts like product pricing, shipping, and other things. I usually use the toFixed() method to make sure that any numbers I calculate have no more than 2 decimal places. So, a price like 2.033 does not help me. It looks like an error to the user, so I need to round the digits to 2.03 so it will display properly.

The problem with using the toFixed() method is that it tends to convert the number to a string after it concatenates the digits after the decimal place. Then, when I try to do another calculation with the result of the toFixed() method, it generates a NaN error (not a number). I have lost my result and any future calculations fall back to this value of NaN. And not only does it disrupt the number I needed, it also tends to stop your function from completing its task, so the website ends up sitting there doing nothing. Ugh!

So, what to do?
Well, there are certainly times when you want the result to be a string. Maybe you are doing a calculation only once and want to add a prefix string like “$” to it to show “$2.03”, or something else. Great. toFixed() is certainly your guy for that job.

However, I have found that for my needs I really need something that will consistently return a number that I can continue to manipulate as a number datatype and not a string datatype.

My solution was simple: create my own decimal-trimming function. I call it trimNum(). The code below will add it to the prototype object in JavaScript so it will be accessible to all Number objects in your Javascript code. All you need to do to to use it is the following:

yournumnbervariable.trimNum(2);

The result will ALWAYS be a number with no more than the requested decimal places (in this case we wanted 2, but you can specify any number). You can also pass it a second parameter like “ceil” and “floor” so it will use the Math.floor() or Math.ceil() method to round the number. If no second parameter is passed, the method simply falls back to using the standard Math.round() method.

If you want to try it, you can go to this page.

Or you can download the source code here.

The solution…
So, here is the basic code that adds the method to all Number objects:

// a replacement for the toFixed() function in javascript (which seems to have problems)

Number.prototype.trimNum = function(places,rounding){

(rounding != 'floor' && rounding != 'ceil') ? rounding = 'round' : rounding = rounding;

var result, num = this, multiplier = Math.pow( 10,places );

result = Math[rounding](num * multiplier) / multiplier;

return Number( result );

}

You call it simply by doing the following, where num is your number you want trimmed, and places is the number decimal places to trim the number down to, rounding is simply the type of rounding you want. Use ‘floor’ to round number DOWN, ‘ceil’ to round them UP, and ’round’ to use standard rounding where if the number is 5 or more it gets rounded up, and if it is below 5 it gets rounded down. Pretty simple.

usage: num.trimNum( places, rounding );

The variables “places” and “rounding” can be either numbers, or variables. The variable “num” needs to be number to work properly. If you are not sure you can use the parFloat() or parseInt() methods to coerce the number before you pass it to the trimNum() method.

A line-by-line explanation of the code
Here is what the code does line-by-line. After the comment we have the “Number.prototype…” line. This adds the method called “trimNum” to the Javascript prototype object. This will make it available to all current and future Number object in your code.

The next line “(rounding != ‘floor’ && rounding != ‘ceil’)…” is a Ternary way of basically asking if the parameter “rounding” is not equal to “floor” or “ceiling” then it needs to be “round”. This is helpful to make sure the method does not stop working if you misspell the second parameter. Also, it allows us to call the trimNum method using only a single parameter (the number of decimal places we want to trim).

The next line “var result, num = this, multiplier = Math.pow( 10,places )” sets up our initial variables and also makes sure that our multiplier is set to 10 to the power of 10(x) times. So, if you pass a 2 to the method it will use 100 as the basis for extracting the last two decimal places. If you send it a 3 it will use 1000, and so on.

The next line “result = Math[rounding](num * multiplier) / multiplier” simply take the number and multiplies it by the multiplier. It then rounds the result using the appropriate Math.round method and finally, it divides it by the multiplier to put the decimal place back where it belongs.

Good luck!
If you have any improvements on this code, I would love to hear about them. But for now, I hope this helps others avoid the pitfalls of using toFixed() when you need a number instead of a string result. Sure, you could simply take the result of the toFixed() method and convert it to a number, but after the tenth time you need to do that, it gets a little tiresome. Also, the more lines of code you have to generate, the more chances there are for making mistakes in your code. I love the jQuery slogan of “do more, code less”.


Make Your jQuery Website Buttons/Links Work with iPad/iPhone

May 30, 2011

How to Make your website buttons and links work on the iPad/iPhone without massive customization.

This tutorial requires an intermediate understanding of JavaScript, HTML, CSS, and jQuery. Also, I will supply a sample in plain JavaScript, but this solution works best if you are using the jQuery API to build more cross-browser compatible web pages.

So…
You just completed your latest website for a client. You used jQuery to help eliminate all those pesky browser-specific idiosyncrasies and everything works flawlessly in the dreaded Internet Explorer 7/8/9 as well as all other popular browsers. You have even managed to convinced the client that there really is no need to support versions earlier than IE7.

However, there is one issue on which the client will not bend. They are convinced by all the media-hype that if their new site does not work flawlessly on the iPad that their company will not be taken seriously and their sales will plummet. That is why you decided to give Adobe Flash a miss and stick to the workhorse technologies of HTML, CSS, and JavaScript. How could you go wrong? These are the most ubiquitous technologies on the World Wide Web and are supported (almost) fully in every browser. Also, you have decided to use the jQuery API to handle cross-browser compatibility since it is so ubiquitous and easy to use.

But when you pull up your new site, the one that tested so well in all other browsers, you are finding out that most of your links and buttons are not working properly. Some work, others don’t and no obvious pattern emerges to explain these weird behaviors. What the..? Hey! a link is a link, right? Well, not necessarily. The one thing that most web designers forget about the iPad is that it has no real mouse, so there is no cursor, which means their is no actual “:hover” state for DOM elements. In fact, there are no mouse events at all. They all get synthesized by the iPad and fed to the apps that are listening for them in order to maintain compatibility across websites. At least that is the theory, but like all theories they rarely work as well in practice.

What is Going On?
You see, your web page is at the mercy of the iPad’s web browser, Safari. It looks at your page and IT decides if a page element is clickable or not before it sends the synthesized mouse event. If it doesn’t think an element is clickable then no touch events are generated which means no mouse events get simulated and passed on to your web page. And if the browser doesn’t talk to your page, then your page will just sit, doing nothing, waiting for some sort of input.

Don’t worry, there is a pretty simple solution. Let me explain what I discovered about the iPad and HTML. I found out through a lot of research, that it appears the iPad is looking at your page elements and seeing if they contain an event property called “onclick”. If this property is not on the element then the iPad simply ignores it – even if the users is furiously tapping the element on their iPad. The iPad has determined that it is not an element that can be interacted with – it doesn’t even try to send the event to the element. It just doesn’t bother. View a demonstration of this here.

It seems that natural links, like the <a> tag have this handler by default when they contain the “href” property. So, these types of links tend to work fine with no further modification. But, other elements like the <div> element don’t have this event property by default. They don’t normally need it simply because a <div> is not a link right? Well, it’s not, but many designers use it as a clickable element that contains an image button, label, or other item that they want the user to be able to interact with. The <a> tag is not the most flexible of elements, and sometimes your design calls for other elements acting like links; not trying to force links to act like other elements.

Why Not Just Use Straight Javascript?
Now, if you are using straight, plain JavaScript, then you probably have not run into this problem simply because when you use the traditional method of adding an event listener to a DOM element via Javascript, it handles adding the function to the element for you by way of setting its definition. For example:


// addling an event listener the traditional, plain javascript way.
document.getElementById ("button_3").addEventListener ("mousedown", function () { alert('I was clicked') }, false);

So, why not do all of your event listeners this way? Well, for one thing pre-version 9 Internet Explorer does not work this way. Only newer versions like IE9 deal with event listeners in this way. So, you would have to have two different methods for each DOM element. One to do it the IE way and the other for most other browsers. And that is the biggest reason to use an API like jQuery – it insulates you from the need to code different ways of doing the same thing for different browsers. But, like all solutions, jQuery can also create some unexpected problems. Because jQuery essentially wraps DOM elements in order to make them more flexible and cross-browser compatible, it also insulates your jQuery listeners from the synthesized iPad mouse events which it needs to handle any mouse event-related actions.

I was not looking forward to being required to handle two sets of events for the same actions. I wondered, instead if it was possible to simply force a bridge between the iPad and the web page to get it to synthesize the appropriate mouse events based on its own translation of its touch events. Could I make the iPad believe that the elements I wanted to be buttons and links, really were buttons and links and therefore, it would communicate with my jQuery event mouse event listeners?

My Solution
Well, that is exactly what I did. I simply made sure that if the page was being viewed on an iProduct (iPad/iPod/iPhone) that the “onclick” property was appended to each element before the page ran. This way, the event could pass through the jQuery element wrapper and trigger the element’s own onclick event handler, which then triggers the jQuery event handler in the wrapper! Wonderful! View a demo of this effect on here. You will need to visit this link on your iPad to see it properly, otherwise all of the links will work as expected.

Before I show you the actual code I used (which you can also download here), I want to walk you through the logic of the process:

  • The page loads into the browser and the function “startUp()” is triggered by the page-ready event.
  • I read the user agent string and see if it contains an occurrence of the words “iPad/iPod/iPhone”. Don’t worry about any other identifiers except for these labels, since version numbers will change over time and you do not want your page to break due simply to old age.
  • If the page is NOT on an iProduct, then I ignore the next step and simply display the page.
  • If the page IS an iProduct, then I use jQuery to get an array of all of the classes of elements that I want to make sure have the “onclick” property.
  • After assigning all of the elements an empty “onclick” event, the iPad should now think that it is supposed to pass all simulated mouse events to the page element which can then echo the mouse event to the jQuery event listener for that same element.
  • The page should behave as it does in all other browsers that it functions properly in.

It is actually a pretty simple process, but it took me forever to nail down exactly what the problem with my page elements was.

One warning, though. Simply adding the “onclick” property is not a 100% guarantee that things will work perfectly. On occasion, I have noticed that if an element is nested too many times inside of other elements that it does not always behave predictably. In these rare cases, I simply add my event listener to the parent container that my element is nested inside of.

Okay, now the code. Click here to download all the code in a zip file. You will need jQuery (which is included in the zip download) in order to run it properly.


<html>

<head>
<!-- create a style definition for our button class -->
<style type="text/css">.button { width:250px; height:auto; position:relative; top:50px; left:150px; text-align:center; font-size:14px; color:#FFF; line-height:24px; background-color:#F00; }
.button:hover{ cursor:pointer }
</style>
</head>

<!-- LOAD OUR JQUERY HERE -->
<script type="text/javascript" language="JavaScript" src="jquery-1.6.1.min.js"></script>

<!-- ASSIGN OUR LISTENERS -->
<script type="text/javascript" language="javascript">

// add q jquery listener for the document ready event
$(document).ready(startUp);

function startUp()
{

//see if this is an ipad/ipod/iphone
if( String(navigator.userAgent).search(/(iPad)|(iPhone)/i) > 0 )
{

// add an onclick event handler function for all items that need it so the iPad/iPhone will pass it touch events as mouse events!
$('.onclick_button').each(function(){
this.onclick = function(){ alert( $(this).attr('id') + ": I have an onclick event property!") };
});
}

//now, add regular jQuery listeners to the first and second buttons, but only the second will have the additional onlick property added
$('#button_1, #button_2').live('click',function(){ alert( $(this).attr('id') + ': has received a jQuery event!') });

//also assign a listener the traditional way to button 3 (works in all browsers except IE 8/7/6/5 and lower )
var button3 = document.getElementById ("button_3");
button3.addEventListener ("mousedown", function () { alert('button_3 received a javascript event.') }, false);

};
</script>

<body>

<!-- our first button has NO onclick event property -->
<div id="button_1" class="button">jQuery: no onclick!</div>

<!-- our second link has one added after page ready... -->
<div id="button_2" class="button onclick_button" style="top:150px;background-color:#006600;">jQuery: with onclick!</div>

<!-- our third link has only a plain javascript event listener -->
<div id="button_3" class="button" style="top:250px;background-color:#C90;">Javascript: using addEventListener</div>

</body>

</html>


Successfully Searching Multidimensional Arrays in AS3

July 15, 2010

Please be aware that this tutorial is intended for intermediate-to-advanced ActionScript programmers and designers. It is therefore assumed that you have a competent understanding of the underlying principles and specifics of both versions of ActionScript. I cannot respond to all questions regarding this code. So, please assume that you are on your own. Notes, instructions, and any relevant documentation has been included in the FLA files. Also, you will need Flash CS3 or CS4 to read the source files included in this tutorial.

The Problem
There are times when you are creating something in Adobe’s Flash content creation suite, that you want to be able to have an array of arrays. These are called multidimensional arrays, and they are great for many purposes. Their only big drawback seems to be the lack of searchability in the entire array and sub-array elements.

Multidimensional arrays are like a large red box, with medium-sized blue boxes inside and even smaller yellow boxes in each medium-sized blue box. So, you have the parent array (the red box) and its individual elements (the blue boxes). Each blue box then contains its own array (the yellow boxes).

I Just Can’t Find Anything!
Normally, when you need to find an occurance of some string in another string, you use the handy “indexOf” method like this:

var myIndex:Number = sourceString.indexOf( "my search target" );

And it will generate either “-1” (not found) or an integer which is equal to the target string’s starting position in the source string.

Then try using the “indexOf” method on a regular array and you also get the results you expect. But try the same method a multidimensional array and things just fall apart. You get nothing but the dreaded “-1” result: the string you were looking for was not found anywhere in the array. Even if you search in each array element individually, you must still look for only EXACT matches (===). You cannot find partial matches like you can when searching a standard string.

PARTIAL SEARCH FORMATS THAT FAIL

  • myArray.indexOf( “find this” ) = FAILS!
  • myArray[ element0 ].indexOf( “find this” ) = FAILS!
  • myArray[ element0 ][ element0 ].indexOf( “find this” ) = FAILS! (returns the starting locating in the array element string, but not the array index!)

Let there Be Light.
Ooooooh! Pretty colors… I have finally come up with a SIMPLE, quick solution to finding strings in multidimensional arrays. I do it by using the “forEach” method on an array. It passes the array element, index, and entire array object to a function which can then pick through the contents to look for partial matches and return an array on the array object that contains ALL of its instances in the parent array. If you read the results array, it is a set of row and column indexes that can be used directly on your parent array to display the contents of the elements that contain your search target string. It all sounds a bit confusing, I know it took me a while to get my head around the problem, but once you read and run the code below, it will become really clear just how simple and useful this code can be.

And Now, the Code, Please…
Click here to download the CS4/CS3 FLA file. You may use this code as part of any project as long as you do not sell my code on its own or as part of any large, commercial project. This code is copyright 2010 Clarence “exoboy” Bowman, all rights reserved.

Also, Here is the Code For you Copy-Pasters
// set up a multidimensional array that contains some data
var myArray:Array = new Array();
myArray.push(["granola","people... are great"," 4 ","10"]);
myArray.push(["bill","orangutan","buster","keaton"]);
myArray.push(["steve","gates","24","yes, sometimes"]);
myArray.push(["help","dave","jobs","hal"]);

// here we set up some properties on the array object to hold our search string and our results
myArray.myTarget = "ste";
myArray.myResults = [];

// now we call the search
myArray.forEach(multiSearch);

// this is the function that does all the heavy lifting....
function multiSearch(element:*, index:int, array:Array)
{
// see if we have a match in this array and pass back its index
for(var i:* in element)
{
if( element[i].indexOf( array.myTarget ) > -1 )
{
var tempArray:Array = array.myResults;
tempArray.push([index,i]);
array.myResults = tempArray;
}
}
}

// -------------------------------------------------------------------------------
// all the code below is OPTIONAL... it is just to show our results
// in the output window in Flash so you know it worked....
var printArray:Array = myArray.myResults;
for(var i:* in printArray)
{
trace("TARGET FOUND @: "+printArray[i][0]+", "+printArray[i][1]+" = "+myArray[ printArray[i][0] ][ printArray[i][1] ]);
}
// -------------------------------------------------------------------------------


Flexible, Dynamically-Expanding Columns with Absolute Positioning

April 22, 2010

April 22, 2010
 
To use this tutorial, you will need Prototype.js (v1.6) and a good working knowledge of javascript, CSS, and XHTML. This tutorial assumes you are an intermediate-to-advanced javascript programmer and understand the basics of programming and code design. I will keep the technical jargon to a minimum, but some concepts are just too basic to be covered in great detail here.
 
All of the files you will need are in this self-contained ZIP archive:
 Download this article’s source code here.

 

 
Question… 
How many of you out there have wanted multiple columns of content on web pages without all of the required housekeeping drudgery to make sure all the content gets displayed properly and nothing gets clipped, overlaps or gets shoved around by other elements? And without the fear of getting a call from your client, telling you that the site does not look good in browser X? From the search results I came up with, it would seem that there are a LOT of others like me out there who are looking for a simple solution that does not required executing acres of processor-intensive code. If your page is torturously-slow, what good is pretty content?
 
It has been extremely frustrating finding something that is flexible with a minimum of customization and that works on all browsers. Of course, I am not talking about supporting legacy browser versions, like Internet Explorer 6 and older… that is a COMPLETELY different beast with razor teeth and slathering jaws waiting to clamp down on your unsuspecting ankles. So, for the purposes of clarity and simplicity, I am going to focus only on Safari 4 (mac) / 4 (pc), Opera 9 (mac) / 10 (pc), Chrome beta (mac) / 4 (pc), Firefox 3 (mac) / 3(pc), and Internet Explorer 7 (pc) / 8 (pc).
 
So, Why Bother? 
Good question! Couldn’t this be done using pure CSS? Theoretically it is possible to create a wrapper DIV, and then simply insert column DIV’s into the wrapper. Then, you would use the “display:inline-block” style to stack them left-to-right, or you could use the style “float:left” to take it out of the layout-stream. You could also assign the style “height:auto” to each column to have them automatically expand or contract the column DIV height. Well, theoretically, if you did not want any padding, or margins, or extra spacing around your columns this would seem like the obvious path to success… however, this is not an ideal world. Because of browser differences and flat-out incompatibilities, it will not work this easily. For example, if you used the float method, then because it is not a part of the document-flow, it will not adjust the height f the parent DIV that it is contained in: content will begin to spill out of the bottom of your wrapper DIV, ruining you nice, organized layout. As for the display method, it is lacking since the tops of the column DIV’s will tend to shift up or down depending on the height of its neighboring DIV… so many issues!
 
Trust me, I have tried just about every combination of CSS styles imaginable. Sometimes they worked great in 2-out-of-3 browsers… but then almost is never going to be good enough when it comes to websites, is it? That is where Javascript comes in. With it, we can create a robust solution that ALWAYS works and gives us predictable results every time.
 
Also, most of the current solutions out there only resize things at the time of the page load. This solution updates all the time, since there are times when you want a more expandable-contractable page design.
 

What This Tutorial IS NOT… 
This tutorial is meant to be a starting point only. All code has been commented inside the Javascript and XHTML, and CSS. You may copy-paste this code and use it for any purpose commercial, or private, as long as you are not selling the code itself and it is an integrated part of an actual webpage project not intended to solicit sales of this code.
 

Let’s Get Started 
To begin with, let’s introduce the technologies we will be using to achieve these automated, absolutely positioned columns of content. I decided to do everything in as few technologies as possible and using things that would be updated and open-source for a long time to come. I settled on Prototype.js for my cross-browser support, and CSS/XHTML for everything else. Prototype.js is a javascript-expanding system which is widely used, fully supported, and is ALWAYS being extended by others and updated. So, there is a pretty good chance that it will be around for years. The other nice thing about Prototype.js is that the code you need for your pages will reside on the same webspace as your site, and is not retrieved remotely, so if your page works now, it should work until your webhosting provider makes enough changes in their webserver configuration that it breaks your site. Besides, the average life-span of a website is typically 3-5 years. Anything beyond that is an amazing, unexpected bonus.
 

Prototype.js extends Javascript quite well, and it allows me to write smaller, faster code that is rather cross-browser compatible. So, I created my functions in an external javascript file and simply import them at load-time for use in my page.
 

Our Logic Flow 
What I needed was a container (wrapper) DIV that would hold multiple columns (DIV’s). Each wrapper-enclosed DIV would become a vertical column of content that would dynamically expand or contract its height according to how much content was enclosed. As the columns approached or receded from the bottom of the wrapper DIV, it would enlarge or reduce the height of the wrapper DIV so that our longest column maintained the same distance from the actual bottom of the wrapper DIV. Also, the page needs to be able to update itself upon load and anytime that a column changes height. Oh, yeah, and everything needs to be positioned absolutely so I could control the layout exactly the way I wanted it. I also wanted header and footer elements that could act as either visual spacers, or as holders for page-cap graphics. A lot of times, when I create a “page” of content within a web page, I like to give it a visual top and bottom so that it stands out more from the rest of the content on the page.
 

How We’ll do It 
We will accomplish self-updating columns by using an event listener for any click on the document. This will execute a function called “pageSnap” which will adjust the page_wrapper DIV height in relation to its contained column DIV’s. Also, instead of calling each column of content by name, we will simply create an array that holds every element of the class “page_column”. This will come in very handy later when you want to make your layout a 3, 4, 5… column layout. Since the columns are called by their class and not by their id, you can name the actual column DIV elements anything you like. They just need to be assigned to the class “page_column” to be included in the self-updating process of the wrapper DIV.
 

Our Page Structure 
Below is a simple diagram of how our DIV elements are structured. A copy of this diagram is included in the source code for this project. As you can see, all of the individual DIV elements that make up our page of content are contained in a single wrapper called “outer_wrapper”. While this wrapper is not necessary, it does gives us the flexibility to take the entire chunk of elements and simply drop them into a new page design. By enclosing all the elements together, it keeps them from spilling out into other page elements and interacting in an undesirable way.
 
The names of each element also correspond to that element’s CSS class definition. Since class and id do not share the same namespace, your browser should handle these just fine. If you do run into some future, unforeseen conflict, you can always change the class names in the CSS, just make sure you change them in the imported CSS file as well. I have been using duplicate class and id names for a while and have yet to have them conflict… but that does not mean it will stay that way forever.
 

Let’s Dissect Our Code 

Click here to see a working version of this example code.
 
Click here to download the source code.
 
Okay, so now you have the basic logic, the “why should I bother”, and the overall element structure down, so let’s move on to dissect our code block-by-block. But, first, let me tell you that I am only going to go over the relevant code blocks. I refrain from describing all the code in the Javascript, CSS, and XHTML files since they have all been thoroughly commented.
 


document.observe("dom:loaded", startup);

 1. This block of code assigns an event listener for the DOM event “loaded”. Since this fires before the onLoad event on the body element, it makes a great “pre-startup” startup handler. Just be sure to practice good-housekeeping and remove the listener after you no longer need it.
 

var pageWrapper, footer;
 
2. Here we add a couple of variables to the DOM for later use. We do not want to assign them to their respective page elements yet, because those have not been registered with the DOM yet and will simply return an undefined element, which will break the page and nothing will resize properly, or at all. Now, we do not have to create an instance of these variable names here, but it is good practice to do it this way, in case we want to add other functions that might use these variables. We could avoid globals altogether by placing our variables as properties on the element itself, but that is another article altogether. For now, we will keep things as simple as possible.
 

function startup()
{
// turn OFF the event listener?s
document.stopObserving("dom:loaded", startup);

// [ OPTIONAL CODE BLOCK ]
// these are OPTIONAL and should be removed when you create your own layout
// they are only here to allow you to shrink and grow the test columns to see how the page functions.
// assign some listeners for our shrink/grow buttons
$('clickable_1').observe( 'click', function(myEvent) { stretchElement("20",myEvent) } );
$('clickable_2').observe( 'click', function(myEvent) { stretchElement("-20",myEvent) } );
$('clickable_3').observe( 'click', function(myEvent) { stretchElement("20",myEvent) } );
$('clickable_4').observe( 'click', function(myEvent) { stretchElement("-20",myEvent) } );
// [ /OPTIONAL CODE BLOCK ]

// get a handle for the page_wrapper main div holding your columns
// you could name your page_wrapper anything, just make sure you change the name here as well
pageWrapper = $('page_wrapper');

// assign a height offset value for out footer element. If it does not exist, it will return a zero height
try {
footer = $('page_footer').getHeight();
} catch(e) { footer = 0 }

// set up a listener for a click on the document since we do not know which elements will expand or contract out layout height
// we need to check every time for changes in the height of the pageWrapper DIV
document.observe( 'click', pageSnap );

// DON'T FORGET! You can update the page_wrapper height any time simply by calling this function.
pageSnap();
}

 
3. This is the function that will run AFTER the page has loaded and registered all the page elements with the DOM. Now, we can assign our elements to their respective variables and thereby get a valid handle for later use. You will notice that there is a stopObserve method called on the document object. This is where we stop listening for the “DOM:loaded” event.
 

pageWrapper = $('page_wrapper');
 
4. Here, we assign our “page_wrapper” element to the global variable “pageWrapper”. This will give us access to that element without having to change the occurance of the element name more than once.
 

try {
footer = $('page_footer').getHeight();
} catch(e) { footer = 0 }

 
5. There are times that you may not want a footer element. You cold simply assign the element a height of zero, but for the sake of robust code, I wanted something that would allow me to remove the “page_footer” DIV altogether without breaking my page. So, if the element does not exist, it simply ignores the error and assign a height value of 0 to the variable “footer”.
 

document.observe( 'click', pageSnap );
 
6. Here is where we now add an event listener to the document element. This allows us to automatically check our “page_wrapper” height without having to call it from every function that might resize our “page_column” DIV elements due to a user click on some size-changeing UI element. You could just as easily assign this listener to the “page_wrapper” element instead of the “document” element. But, for the vast majority of purposes this works best.
 

pageSnap();
 
7. Once the page loads, our “page_column” DIV’s may have already changed size due to font-size differences among browsers and font families. So, it is always a good idea to execute this function to make sure everything is adjusted right away.
 

function pageSnap()
{

// get a the object that was acted upon to get it to this function
var target = pageWrapper;

// calculate a starting prevHeight (previous height) of the page_wrapper DIV
var prevHeight = 0;//target.getHeight() - footer

// this creates an array of all child elements in the target parent (page_wrapper) that are of the class "page_column"
var targetKids = $( target ).select('[class="page_column"]');

// go through all page_column elements and adjust the page_wrapper DIV height
for(var index=0;index prevHeight )
{
target.setStyle({ height:String( (height + footer) + "px" ) });
}
// save our current height as the prevHeight variable for reference on the next "page_content" column
prevHeight = height;
}
}

 
8. This is the function that will make the actual column adjustments. For the sake of simplicity, I have assigned the “pageWrapper” handle to a new variable called “target”. Of course, you do not need to do this, but I like to reassign our global to a local variable so that there is only a single instance of my global in my function definition. Also, if I wanted to have this function work on multiple “page_wrapper” element in a single webpage, I would just have to assign our “click” listener to each “page_wrapper” instead of the document, and then assign the “wrapper” variable to the “this” variable which would give us a handle to whatever element called the function without having to track all the different names of a the different “page_wrapper” DIV elements.
 

var prevHeight = 0;
 
9. Here, we want to create a variable to hold the previous height of the last “page_content” column whose height we compared to the height of the “page_wrapper” element. I assign it to zero, simply because of we try to add it to another integer and then assign it the height style property of an element, it will break our page in some browsers. By setting its inital value to 0, it helps to guarantee that we do not get some erroneous starting value.
 

var targetKids = $( target ).select('[class="page_column"]');
 
10. Here is probably the trickiest part of our code. What the select method allows us to do is collect all the occurances of the “page_content” class into a single array that we can iterate through and compare each element individually to the height of our “page_wrapper” DIV.
 

for(var index=0;index prevHeight )
{
target.setStyle({ height:String( (height + footer) + "px" ) });
}
// save our current height as the prevHeight variable for reference on the next "page_content" column
prevHeight = height;
}

 
11. Here we create a loop that will iterate through all of the elements in our “targetKids” array. Now, we could have done this with an each method and assigned our function to each of the elements themselves in the array, but for the sake of simplicity, I decide to just use the tried-and-true for-loop. Unless you have many, many elements to be compared, you should not notice any really appreciable speed difference.
 

var kid = $( targetKids[index] );
 
12. Here we assign our first element in the array to a shorter variable name. There is just too much room for error to have to type, retype, or even copy-paste the long name of “$( targetKids[index] )” every time we need to reference it. The shorter your variable names the less chance of typos.
 
 

var top = parseFloat( kid.getStyle( 'top' ) );
var height = kid.getHeight();

 
13. Now, let’s get a floating-point version of the values stored in our style property “top” and “height” on the “kid” element.
 

if( height + top > prevHeight )
{
target.setStyle({ height:String( (height + footer) + "px" ) });
}

 
14. Now, let’s add the height of our “page_content” column to its “top” style value to get its actual height inside the “page_wrapper”. If our content is now taller than the holding DIV element, we adjust the height of the holding DIV to the same as the height of our “kid” element PLUS the height of our “page_footer” element. This will make sure our holding DIV stays taller than or “page_content” DIV.
 

prevHeight = height;
 
15. So, all we need to do now, is save the current height value for comparison against the height of the next element. Using this value gives us a simple way to make sure that if the next column is taller than the last, we need to increase our “page_wrapper” height. Otherwise, if the next column is shorter, we can simply ignore it and keep the “page_wrapper” height unchanged. This way, we do not need to compare every column to every other column every time we look at each column height.
 

16. Also, make sure that if you want to move your columns, or add columns, you duplicate the “page_column” DIV element, give it a unique instance “id” and override any “left” or “top” properties using an inline style definition. The default position for all columns in the CSS class definition for page columns is at top:0, left:0.
 


 

Thanks 
That is about it. Pretty simple, actually. But not necessarily obvious. So, I hope this tutorial has helped.
 
Download this article’s source code here.


Google, adWords, ActionScript 3, and Me

February 17, 2010

Please be aware that this tutorial is intended for intermediate-to-advanced ActionScript programmers and designers. It is therefore assumed that you have a competent understanding of the underlying principles and specifics of both versions of ActionScript. I cannot respond to all questions regarding this code. So, please assume that you are on your own. Notes, instructions, and any relevant documentation has been included in the FLA files. Also, you will need Flash CS3 or CS4 to read the source files included in this tutorial.
————————————————————————————————-

Q: How do you get Google’s adWords program to support ActionScript 3?
A: You don’t… well, sort of.

Recently I needed to create some banner ads of varying sizes that could be injected into Google’s adWords ad-delivery system. I diligently went to the link Google provides with the ad specs and read up on what sizes and formats were acceptable by Google.
 
I guess I should have read a little more carefully because I blithely created all my ad banners in AS3, assuming that since AS3 is more than four years old, it would be supported by Google. I use AS3 exclusively now because it is much more object-oriented and it uses an event-based architecture and offers me far more options than does the older, slower, less-efficient AS2 (ActionScript 2).
 
After I coded all of my banners, I submitted them to Google for approval and testing. The banners were pretty simple in architecture, so I figured they would be relatively trouble-free. Wrong. I received an email from my Google ad rep saying their system was rejecting the SWF banners… The reason (as you may have already guessed)? Their system does not currently support AS3, and there is no projected date for supporting it.
 

Big Trouble

Let me just say that I have always thought of Google as being a bit more on the cutting edge of technology than they turned out to be. When I say “cutting-edge”, I am not referring to the any of the latest-and-greatest technology. To me, this is what I would consider “bleeding-edge” technology. This is where the pioneers and beta-testers live. So, since AS3 is no longer bleeding-edge technology, I just assumed they were currently supporting it. Well, they don’t support it now and they do not have a plan to support it any time soon.
 
 

What to do?

So, rather than hurl myself off my chair, or spend hours recoding my ActionScript code into AS2, I decided to try and create a work-around that would allow me to submit a Flash AS2 SWF that would meet their restrictions, but would still allow me to leverage all of the goodies in an AS3 SWF for my client.
 
What I ended up creating was essentially a “lifejacket” for my ActionScript code: I created an AS2 SWF that acted as a loader and clickTAG value-passer to an AS3-based SWF that would be loaded into the same security domain and replace the older, AS2 SWF.
 
It was a bit tricky since Google has all kinds of code and function-call restrictions. They basically filter your SWF and look for any potentially “offensive” code. Hey, I completely understand the need to control the content that you are distributing for people… but there must be a better, more efficient way of handling this. Their current system needlessly punishes those of us who have a legitimate, innocuous use of more advanced functionality. Because of this fear of abuse, we the designers and programmers all have quite a few hoops to jump through to keep our work fresh and relevant. Besides, all of the ads require pre-approval of content before they can ever be launched, disseminated, or viewed by anyone so the chances of getting anything by Google (unless they just aren’t paying attention) are pretty much zero.
 
WARNING: Be careful what you try to build into your AS3 code. Never forget that Google has to approve your ad and if they do not think it is appropriate, at any time, working-or-not, they will shut it down, delete it, or just completely ban you from using their adWords service.
 
 

Onwards!

Okay, so I created my AS2 code to load in my AS3 code and run in the same domain, thereby meeting all of Google’s criteria and also my own. It really worked!… well, sort of. It was not a perfect solution yet. Google’s supplied “clickTAG” value was getting chewed up somehow in transition and so the ad was not going to the destination URL that it was supposed to go to. The new ad failed Google’s testing.
 
 

The Final Solution

I ended up solving my problems like this…
 
1. I placed Google’s clickTAG AS2 code into the first frame of an empty movieclip. This would act as my “button” for Google, but would not really be used, but it would allow any code search by Google to come up as successful.
 
2. I then had to create a URL string from some ascii character codes, since Google does not like to see URL prefix “http://&#8221; in their code. They are worried you will circumvent their pay-by-the-click system. I say, if you are willing to submit your source code to them and to be held up to scrutiny, then you should be able to include code like this, but they have a more binary policy. It is either acceptable or not. As long as you are not doing something malicious, there should be no problem. But beware those who have not-so-good intentions. Google isn’t a huge mega-corp for no reason. They could squash you, so be careful!
 
3. Once I programmatically created the URL string and captured the value of the clickTAG variable, I used a function to change all of the offending URL characters to something that could be passed along with the URL and would not be encoded, converted, or altered on its way to the newly-loaded AS3 SWF.
 
4. After the replacement SWF was loaded, I then used a regular expression (RegExp) and put back, all of the offending characters from the Google URl so it would now be functional again. [exoboy’s note: regular expressions (RegExp) are NOT available in AS2, are only in AS3, and are INDESPENSIBLE when dealing programmatically with strings!]
 
5. Now, if a user clicks on the SWF, they will be taken to the Google-generated link with all of Google’s tracking still intact.
 
6. That’s it! You can download the simple example source files here.
 
 
lifejacket_source_files

 
SWF add is loaded —-> SWF lifejacket preps Google clickTAG value —> SWF lifejacket replacement SWF —> replacement AS3 SWF re-assembles Google’s clickTAG value —> AS3 SWF runs and user clicks to visit banner owner’s site…
 
These steps solved all of my pre-flight issues with Google, and functioned perfectly upon actual distribution. Now, I will be able to do whatever ad banners I want in AS3 without having to be limited by the donkey-cart that is AS2.
 
 

What to Send to Google…

 The nice thing about this solution is that you only have to send the “lifejacket” SWF to Google for distribution. The actual banner AS3 SWF resides on your client’s domain. The lifejacket even meets Google’s size restrictions. My last lifejacket was only about 4K! All you need to remember is to make the name of the lifejacket SWF the same as the banner SWF, but with an additional “-lifejacket” before the “.swf”: e.g. my_banner-lifejacket.swf would be the lifejacket and my_banner-ad.swf would be the ad that you host on your client’s site.

An Important Note On Security Domains

Just remember, that in order to load an image or SWF from one domain to another, you must have the proper security settings in the SWF that is loading and the SWF that is being loaded. You also will need a properly-formed “crossdomain.xml” file that must be placed in the ROOT directory of the hosted website that you are loading your AS3 SWF from. Otherwise, your loaded SWF will never load or display properly. I have put security settings into the sample code that worked for me. You should start with these, but you may need to adjust them if they do not work for you.
 
 

Sign the Google AS3 Petition!

Click this link to be taken to Facebook.com and join the Google AS3 petition… if enough people demand AS3 in their adWords program… who knows? Maybe they might even think about it.

Copyright 2010

LIFEJACKET™ code and concept by Clarence “exoboy” Bowman
©2010 Clarence “exoboy” Bowman, all rghts reserved clarencebowman.com. You may use this code for anything except resale, provided this copyright info remains embeded in the source code, and credit is given in any documentation.


How to Create Bookmarkable Hash/Anchor (#) Links in IE 5.5/6/7/8

January 17, 2010

Okay, so recently I had a client project that sounded pretty simple: all I had to do was to take their existing Flash website and make it so that they could deep link their samples and different site sections, on-the-fly (programatically) without hand-coding each new link.

The project.

The customer had coded it so that the flash used an XML document and sample names to identify and pull them up. I won’t go into great detail about the Flash, let’s just say that all I did was to call an external function using the ExternalInterface method “window.location.href.toString” and it dutifully retrieved the current URL from the browser of the page that was currently being displayed. 
 
Then, I simply compared the current URL to the one that Flash thought was being displayed. If they matched, I added the URL to the browser’s history. If they did not match, then I loaded the appropriate sample and updated the browser page URL so they both matched. 
 
For those who are interested, I can write an article about the solution above. However, for the purposes of this article I want to talk about a really simple and forward-compatible way to add items to Internet Explorer’s history without having to resort to using someone else’s fancy external javascript, Ajax, Visual Basic, or any other trick code that might break on the next version of Internet Explorer. 
 

Success.

Okay. So I got my solutions to work flawlessly in Flock, Netscape, Safari, Opera, and Firefox. I was thrilled that it only took me about 3-4 hours from start-to-finish. That did not take any longer than I thought it would. Hooray! Then…. I turned around to my craptastic-PC and started testing on all of the browsers under Windows XP. 
 
It simply didn’t work. Not at all. The page just kept-reloading in an infinite loop and NOTHING was being added to the history… After an hour of sobbing, I picked myself up and settled in for the long-stuggle I knew I had ahead of me. 
 
Why doesn’t Microsoft simply add history items like everyone else? Who knows! I am willing to bet that there was a very long and boring meeting about it in Redmond, Washington that sort of went like this:
 
“So, what about adding items to the user’s history?”
 
“Sure. Let’s add whatever they are viewing as a new entry into the history unless it is a duplicate entry.”
 
“Okay. Sounds good. How about when the user visits an HTML anchor link inside the same page?”
 
“Well, let’s not bookmark those. They are not really links.”
 
“Sure they are. They send you to another location and you might want to hit the back button to backup-through them…”
 
“No. That’s dumb. Why would any want to do that? I can’t imagine any reason that people would ever want to do that so, rather than just leave it as a possibility, or make it so people can change a preference, let’s just make it the standard that no hash links (#) indicating anchors will be saved in the history….”
 
The rest is… yes, I have to say it: history.
 

Aaaaaaaarg!

That is all I can say right now.
 
I can think of at least ONE really good reason. And I am sure there are many other people out there who have their own good reason.
 
Hey, Microsoft! Stop deciding what is best for the user and eliminating possibilities that you cannot imagine a use for! Sheesh. It’s like having your parents over for dinner and they continually edit your conversation. Your way is not EVERYONES’ way.
 

The Hash (#) Maneuver.

Now that that’s over, let me tell you how I finally overcame this dreaded “feature” in Internet Explorer:
 
1. I generate my dynamic links as I would in any other browser.
 
2. However, this time, instead of my link looking something like: ” http://www.mysite.com/#sampleID “, it ended up only working when it was formatted like: ” http://www.mysite.com/?sampleID/#sampleID “.
 
3. So, I had to check to see if the current browser was IE (of any flavor) and then format the new URL according to the above sample, starting my new sample URL with a query string (?) instead of simply adding a hash mark (#).
 
What did I learn from this? I learned that IE, for some odd reason, does not think that hash-links (anything starting with a hash mark “#”) are worth noting in the user’s history. The only way for me to easily add the entry to the history was to start my sample URL portion of the page URL with a string query (?). Luckily, IE accepts that any URL with a query in it might be important enough to save. Also, other browsers treat query links in the same way. So, at least we have a sort of pass-through channel for our hash-link.
 
Since the query string gets ignored by the page, unless you capture the variable and use it for something. It was easy to then pass the entire URL to Flash and using the String.split(“#”), create an array that contained the prefix of the URL and suffix.
 
The suffix contained my actual hash-link and so I was able to pull the sample name from it and then tell Flash to retrieve and display the proper sample.
 

Postmortem.

Why… why… why… does Microsoft continually do this to us? Hey, Guys! How about you actually talk to people who use your software and not just listen to the ones who are coding it? Make technology conform to the way people function. Don’t make people conform to the way technology functions.
 
For support of hash-links, I would have to give Microsoft an F-.