txts2myx
Check out my new site – txts2myx! What’s the last text message you sent to your ex? I want to know. txtit!
I'm Christian Cox, an Atlanta-based front-end web developer and occasional designer. Lately I'm focusing on web standards, AJAX, mobile sites, and ActionScript development. I get to work with PHP and some MySQL too, but not quite as often. Roll over the links below to get a description of the work I performed on each project, then click through to check them out.
Web Standards
Ventanas
Sargeway
The Stacks
maybe.for.you.
maybe.for.you. mobile
ParkGrounds
Quickbooks Made Easy
Flash
CDC Flu IQ Widget
Philips Van-Heusen Video Player
Philips Van-Heusen Map
Significant Federation Paparazzi Gallery
The Maverick Group
J&CO Creative
ASV
TRX
Agent VI
Firedog Jewelry
The Greenes
Sputnik Video
Melissa Tabor
Snowden
Apps/Backend
The Iron Spindle
Judson College
The Maverick Group CMS
Here's a sample of some of the technology I'm using to make my life easier:
jQuery
MooTools
sIFR
IUI
SlideshowPro
Campaign Monitor
Web Developer's Toolbar
MC Tween
W3C Validator
A.P.W.B.W.G.T.T.D.
AsianCajuns
Cloudform
Clunky Robot
Designated Dryden
Dosa Kim
Drive a Faster Car
Goldenfiddle
kissatlanta
local ephemera
ThoughtMarker
Urban Medium
TindelMichi: Whiskey Thump
Check out my new site – txts2myx! What’s the last text message you sent to your ex? I want to know. txtit!
Here’s some sample code you can use to connect your Flash signup form to the MailChimp API. I recently had a client with an existing MailChimp account ask to allow users to sign up for their newsletter through their website, which has a full Flash interface. Unfortunately I was not able to find much documentation out there about how to make this work, and it took me some hair pulling to get it sorted out. Finally, with the help of Jesse Peterson and the API team at MailChimp, we were able to get a working version that doesn’t require any additional PHP or other backend scripting. Here’s the AS:
// Edit your MailChimp specifics here.
// You shouldn't have to edit anything but these two variables
// unless you are collecting additional data.
_global.apiKey = "YOUR_MAILCHIMP_API_KEY";
_global.listID = "YOUR_MAILCHIMP_LIST_ID";
// set tab order for form usability
firstName_txt.tabIndex = 1;
lastName_txt.tabIndex = 2;
email_txt.tabIndex = 3;
submit_mc.tabIndex = 4;
// submission
submit_mc.onRelease = function()
{
// show a loading message in case transmission is slow
response_txt.text = "Sending…";
// gather form data
var firstName:String = firstName_txt.text;
var lastName:String = lastName_txt.text;
var email:String = email_txt.text;
// check the email address
// if it's valid…
if(validEmail(email)){
// disable the submit button while loading data
submit_mc.enabled = false;
// set up result xml
var result_xml:XML = new XML();
result_xml.ignoreWhite = true;
result_xml.onLoad = function(success){
// if the user is subscribed successfully, the result set
// will look something like
// <MCAPI type="boolean">1</MCAPI>
// so you can reset the form and display
// the confirmation message.
if(result_xml.firstChild.firstChild.toString() == "1"){
resetForm("Please check your email to confirm your subscription.");
}
// or else there was a data error,
// so you need to parse the error code.
else{
// Convert the error string from XML data to a string,
// then display it in the response text field.
var resultCode = result_xml.firstChild.childNodes[0].childNodes[0].toString();
_root.resetForm(resultCode);
}
}
// Set up a send XML object, even though we're not
// really sending anything in XML.
// All your data will be encoded in the send_url variable.
var send_xml:XML = new XML();
send_xml.ignoreWhite = true;
// Here's where your data is added.
// For additional text fields, add additional merge_vars
// array elements and append at the end.
var send_url:String = "http://api.mailchimp.com/1.1/?output=xml";
send_url += "&method=listSubscribe&apikey=" + apiKey;
send_url += "&id=" + listID + "&email_address=" + email;
send_url += "&merge_vars[FNAME]=" + firstName;
send_url += "&merge_vars[LNAME]=" + lastName;
// And here's how you send/load:
send_xml.sendAndLoad(send_url, result_xml);
}
// or else there's an issue with the email address
else{
// show the email error.
showErrors();
}
}
// validate an email address
function validEmail(inputEmail:String):Boolean
{
if (inputEmail.indexOf(" ")>0) {
return false;
}
var emailArray:Array=inputEmail.split("@");
if (emailArray.length != 2 || emailArray[0].length == 0 || emailArray[1].length ==0) {
return false;
}
var postArray:Array=emailArray[1].split(".");
if (postArray.length < 2) {
return false;
}
for (var i:Number=0; i<postArray.length; i++){
if (postArray[i].length < 1) {
return false;
}
}
var suffix=postArray[postArray.length-1];
if (suffix.length < 2 || suffix.length > 3) {
return false;
}
return true;
}
// delete all form elements and display a response message
function resetForm(pResponse){
submit_mc.enabled = true;
firstName_txt.text = "";
lastName_txt.text = "";
email_txt.text = "";
response_txt.text = pResponse;
Selection.setFocus("firstName_txt");
}
// select the email address and display an error message
function showErrors(){
Selection.setFocus("email_txt");
Selection.setSelection(0, email_txt.length);
response_txt.text = "Invalid email address.";
submit_mc.enabled = true;
}
Want to try it out? All you need to do to get it working is set up your MailChimp account and lists, then edit these variables:
_global.apiKey = "YOUR_MAILCHIMP_API_KEY";
_global.listID = "YOUR_MAILCHIMP_LIST_ID";
Then push your files online or test your SWF directly in the Flash Player (testing in a browser from your desktop may throw a Flash security error). You should be subscribing users in no time. Thanks again to the API team for working with me on this!
10. The bride’s father is wearing his formal camoflage.
9. The ring bearer is wearing his commemorative Dale Earnhardt diaper (and nothing else).
8. The preacher is also the caterer, organist, program printer and volunteer fireman (that’s a separate post).
7. Before the wedding begins, you are forced to listen to a 70-year-old woman salivate over Hugh Jackman to your 60 year-old mother, then use disturbing southern euphemisms to describe the things he could do to her – e.g. “He could put his shoes under my bed ALL NIGHT.”
6. The entire buffet is pork. Pork BBQ. Pork chops. Pork skins with pork chili dip. Dessert pork rinds with sugar, cinnamon and lard icing (ok that last one I made up).
5. The best man proposes a toast to the groom by tapping his Bud Light bottle with his tin of Skoal. “Ya’ll shut up I’mbouta say sumthin.”
4. One of the ushers is late because he’s being issued a ticket and fine by the state wildlife ranger for shooting too many ducks on his daily morning hunt.
3. The reception is in the newest trailer in the newly expanded west wing of the trailer park. Don’t hate.
2. The sod hasn’t arrived at the newest trailer in the newly expanded west wing of the trailer park, and it is raining, so guests must be ferried into said trailer by ATV complete with mud/rain gear and wader boots for each guest.
1. Instead of “Here comes the bride”, the Carolina Gamecock Fight Song is played as the bride walks down the aisle.
I swear it’s like a damn Faulkner novel with my dad’s family. Epic, I tell you!
They don’t mix well, my friends, and American Express should include a very clear warning to that effect on their gift card labels. The problem? Gas merchants may authorize the card for its maximum amount whenever you swipe it at the pump, regardless of how much gas you may or may not actually buy. Last weekend I swiped my card (which had never been used, and carried a value of $100) and accidentally picked up the diesel nozzle instead of the unleaded nozzle. After about 30 seconds trying to fit the nozzle into my tank (the scary thing is how close I came to just squeezing the handle over the tank hole), I realized I was holding a diesel nozzle and replaced it on the pump. So now, that transaction that had been initiated by swiping my card was canceled. No big deal, I can just swipe the card again and use the green nozzle, right? Wrong. The card has already been authorized for its entire value, and now reports a $0 balance – even though I didn’t actually purchase anything. At the time, I didn’t know what had happened and I just assumed there was a problem with the card activation or whatever, so I used another card to get a little bit of gas to hold me to the next station. At the next station, I took the card inside (thinking it needed to be activated at an actual register first) but got declined again. Finally I called AMEX to ask why I was getting declined and the customer service rep explained what had happened at the first POS transaction. I was informed that it could take 7 business days for the discrepancy to be resolved.
To quote Charlie Brown, “ARRRHGHGHGHHG!” It’s just so frustrating, because the customer service rep told me that next time I want to use the card to buy gas, I should take it inside the gas station and get them to charge the card at a cash register. OK, WHY COULDN’T YOU PUT THAT ON THE GIFT CARD LABEL? There is a big sticker over the top of the card with some basic info about how to use it. Don’t you think this would be important enough to tell your customers? I do. OBVS.
Monday
Tuesday
Wednesday
I’m actually really excited about this! Not only do I get to go to classes 8 hours a day, but I get to go to lots of lab classes – at the end of the period they make you turn in all your practice work for a grade. No lie! Lowest scorers have to act out a new Microsoft commercial on stage at the closing ceremony. Lots of “believable” “successful” “creative” computer users proclaiming “I am a PC”?!!?! John Hodgman owns you and your weak sauce computing persona.
I’m also hoping to capitalize on the unreasonably high number of freebies I get that week. The company I work for is paying for flights, room and conference. And hopefully Adobe’s got swag coming out of their square-rim bespectacled eyeballs. Note to self: check the airline’s policy for extra carry-ons.
I get to do lots of different kinds of front-end development at maybe.for.you., and right now I’m cracking on a social networking site optimized for the iPhone. There’s a simple horizontal header at the top with a logo and a few global nav links. That header is consistent from page to page, and doesn’t require any animation. But for the main site content, I’m setting up clickable lists that scroll to reveal more detailed information. It’s basically a stripped-down version of the IUI, but built specifically for this interface using jQuery. There’s plenty of information out there about hiding the URL bar at the top of the screen – a simple javascript function can handle that:
<script language="javascript" type="text/javascript"> addEventListener("load", function(event) { setTimeout(function(){window.scrollTo(0, 1);}, 100); }, false); </script>
Add that in your <head>tag to scroll the URL bar out of the way when the page loads. But with an AJAX-heavy interface, I found that the URL bar isn’t easy to keep out of the way. Links, animation, and scripting can all cause the URL bar to drop down, even if you’re not sending the user to a new HTML page. Eventually I was able to work out my problems, but only after wasting plenty of time with guess-and-check coding – and continuously uploading my updates to the web because I can’t test locally on my iPhone. Anyway here’s a checklist I came up with for troubleshooting the URL bar.
Prevent the default event. It’s not something I always think about, but it’s usually a good idea, and is usually the first thing I check when troubleshooting. If you’re using <a> links to trigger animations, be sure to catch and prevent that default event. If you’re using jQuery to do your animations, this is simple:
$("a.list").click(function(event){
event.preventDefault();
// animation scripts go here
});
Consider the height of existing page content. Is there enough content visible on the screen to fill up the entire available vertical height? If not, the browser will scroll to the top of the page regardless of whether or not the URL is being manipulated. One solution – the CSS min-height property. Of course, it’s not universally supported but since we’re optimizing for iPhone/iPod touch we’re pretty well covered. So I create a class called “page” that includes a min-height of at least 400px – combined with the 80px of my header that should be plenty of vertical space to fill the screen.
/* CSS document */
.page
{
min-height: 400px;
}
So I thought that would solve all my problems but during some of my page animations I was still seeing the URL bar drop down. I’m hiding a page element off the right edge of the browser, and setting its display property to “none”. When a link is clicked, I animate the original page off the left edge and animate the new page onto the screen. Even though I was using a time-delayed callback to hide the first page after the off-screen animation, since I had that line of code before the line displaying the second page the browser detected an insufficient amount of content on the page for a brief moment and scrolled to the top. Here’s the bad code:
$("#leftPage").animate({
"left": "-100%"}, 700, "", function(){
loadPage(event.target.rel);}
);
$("#rightPage").show();
$("#rightPage").animate({
"left": "0%"}, 800, "", function(){
$(".page:eq('0')").hide();}
);
And the corrected version:
$("#rightPage").show();
$("#leftPage").animate({
"left": "-100%"}, 700, "", function(){
loadPage(event.target.rel);}
);
$("#rightPage").animate({
"left": "0%"}, 800, "", function(){
$(".page:eq('0')").hide();}
);
So after a lot of trial and error I worked out most of the glitches with the URL bar. Next week I’m sure it’ll be something else.
Now with more Web 2.0! No seriously, it was time for a site revamp. If you visited the site before, you would’ve seen a big Flash interface that was more experiential than informative. It also had quite a bit of old work (some from school) that wasn’t really very relavent to anything I’m doing now. Unfortunately it was also created at a time before I realized the importance of SCALABILITY. Believe me, once I got a real jobby-job I learned quickly just how much I appreciate setting up a site so that it’s easy to update down the road. So what you’ll see here is less experiential and more content-driven. I’m even including a blog…for now.
You’ll also notice a shift in the types of work I’m showing. In the past there were quite a few examples of design, a lot of Flash pieces, and a limited number of web standards sites. Now you’ll see that I’m focusing more on development than design, and I’m also showing more of my web standards and mobile-based projects. Why? Cause I gets bored, that’s why! I like to be flexible at work, and that means being able to take on many different types of projects: AJAX, PHP, MySQL, iPhone optimized, and even email campaigns are all fair game and I couldn’t be happier. So I’m going to be showcasing work from all of these categories here, mostly just as a repository for myself so I can have a reference in the future.
So yeah, this is the obligatory first post on my new site. It had to be done. Now it’s time to get back to work.