Author Archive

E4X is a tidy little querying language. Of all the new features in AS3, this one is probably the best.

Most people use E4X for retrieving data straight up, which is good if you have your server-side code doing the filter crunching, but if you’re going for chunky data calls, it’s nice to be able to filter on the client-side too. Thankfully, E4X gives us plenty of capability for filtering.

Let’s start by laying out our common data set. I’m using an XML file with automotive data consisting of Makes->Make->Models->Model. You can see the XML file here: AutomotiveData.xml

In my code, I’ve set a variable called xmlData to the value of the data in AutomotiveData.xml. xmlData corresponds to the root node (Makes) in the data.

Basic E4X filters:

Let’s retrieve the list of Honda models:

trace(xmlData.Make.(@name == “Honda”).Models.toXMLString());

“name” is the attribute of the Make node that we’re working with, so you target attributes with the @ symbol in front. Everything inside of the parentheses is interpreted as normal ActionScript, so you can run pretty much any code that you want to inside there, even if it doesn’t make sense. Just remember, in order to actually filter data, you need to run a function that evaluates to a Boolean: true or false.

Multiple E4X filters:

Let’s get all Makes that have models that cost less than $30,000 and have at least 8 models (this will return Honda and Toyota).

trace(xmlData.Make.(@minMSRP < 30000 && @modelCount >= 8).Models.toXMLString());

Now, you’ll notice that I have an attribute called @modelCount that contains a sum of the model count for that Make. If you don’t have that attribute, you could also count quite easily:

trace(xmlData.Make.(@minMSRP < 30000 && Models.Model.length() >= 8).Models.toXMLString());

E4X recognizes Models as the currently scoped Models node, since we’ve already descended to xmlData.Make. It would not work to say xmlData.(Models.Model.length() >= 8) because the scope of “xmlData.” only gets you to Make, not Models.

In the above example, notice that I ran a function, .length() on the XML, and that I in fact ran E4X inside of E4X. You can nest E4X pretty much as far as you would ever need without hitting any limits. If you do hit limts, you should restructure your XML or consider using a filtering function, which I will talk about later.

Nested E4X and Local Variables

Let’s say we want to find all Makes that have a Model that starts with the letter “R”:

var strModelFirstCharacter:String = “R”;
trace(xmlData.Make.(Models.Model.(@name.toString().indexOf(strModelFirstCharacter) == 0).length() > 0).@name.toXMLString());

Notice that we’re running a nested query so that we can keep the Make scope and get the Make.@name attribute. Also, we’ve passed in a variable this time so that we can modify this E4X to run off of any character or phrase.

If a user was selecting the filters, you could also have them pass in a value, like so:

var strAttribute:String = “mpgCity”; //mpgHighway
var intMinValue:uint = 22;
trace(xmlData.Make.Models.Model.(attribute(strAttribute) > intMinValue).@name.toXMLString());

E4X Filter Functions

Something that just using variables above leaves out is the ability to change the greater than operator without a bunch of messy inline code. However, since we can do basically anything inside of the parentheses, you can create a function to handle variance:

function GenericFilter(data:XML, attributeName:String, value:Object, comparison:String = "equal"):Boolean {
    switch(comparison) {
        case "<":
        case "less":
            return data.attribute(attributeName) < value;
        case ">":
        case "greater":
            return data.attribute(attributeName) > value;
        case "=":
        case "equal":
            return data.attribute(attributeName) == value;
    }
    return false;
}

Then, your E4X can be structured as such:

var strAttribute:String = “seating”;
var intValue:Object = 8;
var comparisonType:String = “=”;
trace(xmlData.Make.Models.Model.(GenericFilter(valueOf(), strAttribute, intValue, comparisonType)).@name.toXMLString());

Notice the valueOf() function; this is passing Model nodes into the GenericFilter, which is why that function accepts an XML node as the data parameter. The comparisonType is simply a string that you can pass in. I’m using a switch because I don’t think there’s a way to pass an actual equality or greater than operator as a parameter in ActionScript. You could of course extend GenericFilter() to accept greater than or equal, or do fuzzy logic, whatever you want to do is acceptable.

These E4X filter functions are pretty much the most powerful thing in E4X; you can run anything that you could possibly want to.

More to come…

I’ll update this article with more information as requests come in or I try new things. Keep in mind that E4X attribute filters don’t work in switch statements.

Comments 2 Comments »

Download the Date Utility referenced in this article: DateUtility.as

Despite what you’ve heard, it’s actually really easy to get a Date() with AS3. You just have to know how the right things to say so that you can smooth-talk her a little bit.

Let’s get started:

Get the current date & time:

var dtCurrent:Date = new Date();

This will give you the current date and time, according to the computer that Flash Player is running on. It will use the computer’s timezone and DST settings.

Create an arbitrary date & time:

var dtWhenever:Date = new Date(2008, 4, 7, 16, 5, 30, 250);
This gives you  May 7th, 2008, at 4:05:30.250pm. Take special care to notice that month (4) is zero-based, meaning that January is 0, and December is 11. Hour, the 4th parameter, starts with 0 as midnight, and ends with 23 as 11pm. The constructor is in the format new Date(year, month, day, hours, minutes, seconds, milliseconds).

Adding to and Subtracting from a date:

Fortunately, AS3 makes this very easy. Say that you want to add 4 days to a date. All you have to do is say:
dtMyDate.date += 4;

Remember, .date is the property that you and I think of as the day of the month. So, you’re probably starting to think of some edge cases, such as “what if it’s the last day of the month?”. The great news is that AS3 will automatically bump the month up as well, rather than having September 34th or something silly.

This works with any of the properties of a Date as well. For example:
dtMyDate.fullYear += 1;
or
dtMyDate.minutes += 300

Subtraction works the exact same way, except you of course would say
dtMyDate.minutes -= 300;

Number of days in a month:

AS3 doesn’t easily give you the number of days in a month, such as “April has 30 days”. However, we can use the subtracting technique from above and set a day of the month of “0″, which is the same as the last day in the previous month. So, if you wanted to get the number of days in March, you could say new Date(new Date().year, 2 + 1, 0).date;

This fills in the current year, then a month of 2 (March) + 1 (April), and then sets the day of the month to 0. In the DateUtility class, you can say DateUtility.GetDaysInMonth(monthIndex);. Remember, AS3 uses a zero-based index for months, so January is 0, December is 11; the GetDaysInMonth() function follows that standard.

Difference in days between two dates:

If you would like to find the difference between two dates, you can simply find the number of milliseconds between them with the .time parameter, and then divide that by 86400000, the number of milliseconds in one day.

var dtDate1:Date = new Date(2008, 4, 1); //May 1st, 2008
var dtDate2:Date = new Date(2008, 6, 20); //July 20th, 2008
var difference:uint = Math.floor(Math.abs((dtDate2.time - dtDate1.time) / 86400000));

We use Math.floor so that we don’t get a partial date, such as 20.2 days. Math.abs is so that you’re actually finding the difference between the days. You can of course remove that if you need to know which date is greater than the other.

Switching to a different timezone:

First of all, you need to get back to UTC, which is easy with the Date.getTimezoneOffset() function.

var dtNow:Date = new Date();
dtNow.minutes += dtNow.getTimezoneOffset();

At this point, you have UTC time, and it’ll be easy to convert to a different timezone. Let’s say we have

var timezone:Number = -7; //Mountain time

To convert, this simple math will work:
dtNow.minutes -= (convertToTimezone * 60);

However, you’re quickly going to run into Daylight Savings Time. A silly little way I get around it is with creating an arbitrary date in January and seeing if it has a timezone offset that’s greater than the date I’m working with, like so:

var blnIsDST:Boolean = (dtNow.getTimezoneOffset() < new Date(2000, 0, 1).getTimezoneOffset());

Then, to convert, you can say:
dtNow.minutes += blnIsDST ? 60 : 0;

If you would prefer, I’ve wrapped up all of the timezone switch functionality in my DateUtility.as that you can download. Download DateUtility.as »

Date Formatting

If you want a formatted date that’s more robust than dtNow.toString(), then you can use the DateFormatter class found in mx.formatters.DateFormatter.

var df:DateFormatter = new DateFormatter();
df.formatString = "EEEE, MMMM DD, YYYY @ L:NNA";
trace(df.format(new Date()));

This should print out something like “Tuesday, September 09, 2008 @ 1:41am”. You can see the full docs on the formatString parameter on the Adobe LiveDocs page.

Date()-ing Tips and Gotchas

Remember that the hours, month, and day properties are zero-based. Hour 0 is midnight, month 2 is March, and day 6 is Saturday.

Date.time is the number of milliseconds since midnight, 1/1/1970 UTC, also known as the Epoch: an arbitrary point in time used to store the value of a date. I like to use Date.time to do a quick compare to see if one Date is greater than another, as in the date difference example above.

Also, Date.date is the day of the month, while Date.day is the day of the week.

Please let me know if there’s something I’ve forgotten that you’re interested in.

Download DateUtility.as »

Comments 1 Comment »

There’s been a good bit of talk lately about CSS resets, and how good/bad they are. This conversation tends to come up every 6 months to a year and always gets people excited. This time around, Jonathan Snook’s No CSS Reset is “the culprit”. I think his general sentiment is good, and he comes to almost the same conclusion, except that I’ve actually created the Base CSS file that he speaks of. More to follow…

The Ugly

I’ve seen lots of people use a star reset: * {margin: 0; padding: 0;}. If you use this by itself, and you aren’t resetting margin and padding on other elements like headings, p, and form elements, you are going to get bitten. Hard. Firefox and IE6 are the special offenders here: form elements, especially checkboxes, radio buttons, and selects will get styled especially poorly and need to be restyled with some padding or the arrows won’t appear, or they become impossible to select.

The Bad

The bad is when you don’t do any common groundwork; every project means you start over and you avoid CSS resets like the plague. Ok, so this isn’t really all that bad, but it’s going to cost you a lot of time in the long run, especially if you’re developing on a team. What happens when you have the n00b that doesn’t understand some of the nuances of cross-browser text sizing, or the way different form elements are handled? You’ll probably say “educate them!” or “then don’t let them touch it until they know what they’re doing!”, but that essentially makes them non-productive. It’s bad practice to make CSS more magical than it already is; give everybody a headstart and lay a common framework.

The Good

As usual, we want to find the middle ground.

I think Eric Meyer’s CSS is moving in the right direction, but it’s a bit bare at the end result. I think the point of a base CSS is that it’s supposed to look decent after you’re done so that you don’t have to think about every style. The idea is to make it look very similar cross-browser, not to pull a Dark Ages Catholic Church and reset everything. Eric mentions this in his article, but a lot of people just download and plug it in.

There are plenty of UI frameworks out there that have a common CSS file that they use, mostly filled up with proprietary classes and IDs, but you can often extract bits and pieces from the generic parts to use. The point is, rather than resetting everything, you can instead create a foundation or base for your CSS to at least make it cross-browser friendly, and at least presentable by default.

I’ve been using my current base.css file for about 3 years now, and I update it from time to time. Feel free to use it if you’d like. You can see it in action at http://labs.zorked.com/lib/base.html

Download: Base.css

Comments No Comments »

I ran into IE’s mixed content security alert feature earlier today when trying to load our application’s secure credit application page. Obviously it’s a bad user experience and it looks bad on us so I set out to fix it and found the following things that hopefully will save someone else some time.

The reason for the warning is that you’re on an SSL-secured (https protocol) page that is attempting to load non-SSL (http protocol) content. It’s ok if you’re on an HTTP page and you request HTTPS; you won’t receive the error.

First of all, you should download a tool for HTTP sniffing. I use Fiddler.

Run Fiddler and then browse to the page that is causing the message. You’ll see a bunch of requests go through, most likely. You can ignore any CONNECT requests; anything else should be showing up as HTTPS.

Most likely, you have a script or CSS file that is requesting HTTP content. If you set them all to HTTPS or leave them as relative paths, you should be ok.

For example:
/css/site.css - OK
https://www.example.com/css/site.css - OK
http://www.example.com/css/site.css - Error

Here’s your checklist of things to do:

  • All loaded assets, such as images, scripts, css, favicons, etc. must be relative paths or be HTTPS.
  • All iframes must point to an actual page (relative or HTTPS). No SRC attribute, or an SRC of # or about:blank will raise the error. Some people have used javascript: false; with success.
  • Make sure all requests from your page are HTTPS. Google Analytics and other 3rd-party tools often have a special link you can use for HTTPS.
  • The codebase attribute of an object (Flash, Applets, etc) must be HTTPS. IE doesn’t actually make a request on this, but it does check the protocol for some reason.
  • Anything that returns an HTTP error will cause the error to pop up, since IE considers its error pages to be “insecure”. Of course, the whole browser’s insecure, but that’s another article.
  • If you have a JavaScript that calls removeChild() on a node that has a background image, it may cause this error. You can set outerHTML = ” instead without consequence. Retarded, but it works.

Things that you don’t have to worry about:

  • DOCTYPES
  • XHTML namespaces
  • Links in the page (anchors, not the link element)

The one that got me was the codebase attribute of an object element. I figured it was just too stupid to be the actual problem. Silly me; IE strikes again.

Hope this saves some folks time.

Comments 9 Comments »

By default, browsers with a built-in popup blocker will usually block Flash navigateToURL requests that open in a “_blank” window. For example: navigateToURL(”http://www.google.com”, “_blank”); will generally get blocked. Even if you have a mouse click event to send off the navigateToURL call, it will be blocked.

The good news is that you can get around this behaviour by calling out to JavaScript to handle the request for you. Go ahead and download URLNavigator.as and save it as ~/com/zorked/URLNavigator.as, where ~ is the folder that your FLA or Flex project resides within. In your ActionScript code, import com.zorked.URLNavigator, then call out to method with URLNavigator.ChangePage(”http://www.example.com”, “_blank”); in the mouse event that you’re capturing.

Now, I’ve tested this with a variety of systems, and it works on a lot of them but it’s not foolproof. So far, it works in IE 6, 7, & 8 (beta), Firefox 2 & 3, Opera 9.x, Safari 3, and runs on XP, Vista, and OSX. It may work on additional systems, but my testing is limited. You may also have problems if you embed your SWF in a strange way. It seems to work with most JavaScript embed libraries, but different parameters on the <object> and <embed> could conceivably cause problems.

However, the caveat is this: you CANNOT call this code except within a click mouse event that you’re listening for. Popup blockers will rightfully block an automatic popup, and there is no way around it. If you ask me how to do an auto-popup, I’ll find your house while you’re sleeping; this method is for white-hat developers looking to open a new browser window for good reason.

Additionally, I made an update to the link that was originally saved: Wordpress likes to save files as lowercase names, which Flash had problems with, since the file didn’t match the name of the class. You should be able to download and work with it without having to rename it.

I’m open to suggestions and improvements, and if anyone has access to additional browsers or operating systems that it’s worked for them on, please let me know.

Download: URLNavigator.as

Comments 36 Comments »