The amazing adventures of Doug Hughes

Archive for April, 2009

Find Alagad, Win Big!

Every year Alagad tries to do something to garner some interest during the conferences.  This year is no different.  We may have actually gone off the deep end a bit.  If you want to win an Amazon gift card, a Nintendo Wii, an iPod Touch, or a Mac Mini, you’ll want to track down Alagad employees at CF.Objective() or CFUnited.  We’ll have you answer a short survey and give you a raffle ticket.  The raffle drawing will be held on the third day of each conference.  Click here for more information.

Playing with jQuery Datepicker

I’ve had a chance to play a bit with jQuery’s Datepicker widget and am really growing to enjoy how simple it is to use. I won’t go over a full explanation of the widget, the site has that covered, but just to give a quick example, check out how easy it is to add the control to a form field.

<html>
	<head>
		<link href="/jquery/jqueryui/css/smoothness/jquery-ui-1.7.1.custom.css"
			rel="stylesheet" type="text/css" />
		<script src="/jquery/jquery.js"></script>
		<script src="/jquery/jqueryui/js/jquery-ui-1.7.1.custom.min.js"></script>
		<script>
			$(document).ready(function () {
				$("#theDate").datepicker();
			});
		</script>
	</head>
	<body>
		<input id="theDate" name="date" type="text" />
	</body>
</html>

Nothing terribly complex. I’ve got one line to include the CSS, 2 JavaScript includes (one for the core jQuery, one for jQuery UI), and finally, I can enable the default datepicker by just using a selector and the .datepicker() constructor. Easy as pie. You can view an example of this here.

Ok, so given how easy it is to use, there were two things I wasn’t quite sure of. First, how can I create a date field that only allows you to pick dates in the future. Now to be picky, we can mean two things by that. Today and onward – or just tomorrow and onward. The datepicker widget takes many options, but one of them is a minDate value. What’s awesome is that you can pass in a JavaScript date object, a string value (like 7d), or even a simple number. Consider this simple example:

<html>
	<head>
		<link rel="stylesheet"
			href="/jquery/jqueryui/css/smoothness/jquery-ui-1.7.1.custom.css"
			type="text/css" />
		<script src="/jquery/jquery.js"></script>
		<script src="/jquery/jqueryui/js/jquery-ui-1.7.1.custom.min.js"></script>
		<script>
			$(document).ready(function() {
				$("#theDate").datepicker({
					minDate:0
				});
				$("#theDate2").datepicker({
					minDate:1
				});
			});
		</script>
	</head>
	<body>
		<input type="text" name="date" id="theDate" />
		<input type="text" name="date2" id="theDate2" />
	</body>
</html>

I’ve got two datepicker widets now. The first one will allow today and onward while the second one will only allow tomorrow and onward. You can see this in action here. You can check this demo out here.

Adobe Flex's Tab Navigator and Corner Radius

There are some really fun amazing Flex based music player floating around online. Two music players that have stolen a lot of my time are Seeqpod and JukeFly.

Now here is where my mild OCD comes into play. Both of these applications use Adobe’s Tab Navigator component and both rock the rounded corners. If you look closely, in the top left corner where the first tab meets the rounded content container, there is a small gap in the UI. I know I’m a psycho but lets just explore a few ways to fix this.

The first and most obvious way to fix this is just to indent the tab bar to the right a little. So if we have a cornerRadus of 20 we’ll need to indent our tab by 20 pixels.

<mx:TabNavigator id="tabNavigator"
	tabOffset="20"
	cornerRadius="20"
	height="100%" width="100%">

Another way to accomplish this would be to override the drawing of that particular corner. We can easily do this by extending the HaloBorder class and overriding the drawRoundRect method. Well use this new border skin instead of the default HaloBorderSkin to style our TabNavigator.

Instead of calling super.drawRoundRect and adding additional functionality to this method, I’m actually going to copy and paste most of this method (originally from the ProgrammaticSkin class) and only alter the section regarding the cornerRadius.

// Stroke the rectangle.
if (!cornerRadius){
	g.drawRect(x, y, width, height);
} else if (cornerRadius is Number) {
	ellipseSize = Number(cornerRadius) * 2;
	g.drawRoundRect(x, y, width, height,
	ellipseSize, ellipseSize);
} else {
	GraphicsUtil.drawRoundRectComplex(g, x, y, width, height,cornerRadius.tl, cornerRadius.tr, cornerRadius.bl, cornerRadius.br);
}

Lets replace this section with code that looks like this:

// Stroke the rectangle.
if (!cornerRadius){
g.drawRect(x, y, width, height);
} else if (cornerRadius is Number) {
ellipseSize = Number(cornerRadius);
var squareTopLeft:Boolean = this.getStyle(‘squareTopLeft’) as Boolean;
var topLeftCornerRadius:Number = (squareTopLeft)? 0 : ellipseSize;
g.drawRoundRectComplex(x, y, width, height, topLeftCornerRadius, ellipseSize, ellipseSize, ellipseSize);
}

Now we need to add a Boolean style attribute called ‘squareTopLeft’ to our new class. This is just a flag that enables us to turn on and off our top left corner.

[Style(name="squareTopLeft", type="String", enumeration="true, false", inherit="no" )]

When I’m googling for an answers, I’m often looking to just copy and paste the solution, so here is the full code:

Main app with style:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application layout="vertical"
	paddingBottom="20"
	paddingLeft="20"
	paddingRight="20"
	paddingTop="20"
	xmlns:mx="http://www.adobe.com/2006/mxml">
	<mx:Style>
		.tabNavigatorSquaredLeftCorner{
			background-color: #FFFFFF;
			cornerRadius: 20;
			borderSkin: ClassReference('com.alagad.skins.TabNavigatorSquaredTopLeft');
			square-top-left: true;
		}
	</mx:Style>
	<mx:TabNavigator id="tabNavigator"
		styleName="tabNavigatorSquaredLeftCorner"
		height="100%" width="100%">
		<mx:Canvas label="Red"
			height="100%" width="100%"
			backgroundColor="#FF0000"
			borderStyle="solid"
			cornerRadius="20"/>
		<mx:Canvas label="Green"
			height="100%" width="100%"
			backgroundColor="#00FF00"
			borderStyle="solid"
			cornerRadius="20"/>
		<mx:Canvas label="Blue"
			height="100%" width="100%"
			backgroundColor="#0000FF"
			borderStyle="solid"
			cornerRadius="20"/>
	</mx:TabNavigator>
</mx:Application>

TabNavigatorSquaredTopLeft.as (BorderSkin):

package com.alagad.skins{
	import flash.display.Graphics;
	import flash.geom.Matrix;

	import mx.skins.halo.HaloBorder;
	import mx.utils.GraphicsUtil;

	//////////////////////////////////////
	// styles
	//////////////////////////////////////
	/**
	 * The squareTopLeft style is the boolean value
	 * to square off the top left corner.
	 *
	 *  @type String
	 */
	[Style(name="squareTopLeft", type="String", enumeration="true, false", inherit="no" )]

	public class TabNavigatorSquaredTopLeft extends HaloBorder{

		//////////////////////////////////////
		// const
		///////////////////////////////////////

		public function TabNavigatorSquaredTopLeft(){
			super();
		}

		//////////////////////////////////////
		// overridden functions
		///////////////////////////////////////

		/**
		 * Overrides the drawRoundRect method from the
		 * ProgrammaticSkin class and adds the top left
		 * corner radius option.
		 */
		override protected function drawRoundRect(x:Number, y:Number, width:Number, height:Number, cornerRadius:Object=null, color:Object=null, alpha:Object=null, gradientMatrix:Matrix=null, gradientType:String="linear", gradientRatios:Array=null, hole:Object=null):void{
			var g:Graphics = graphics;

			// Quick exit if weight or height is zero.
			// This happens when scaling a component to a very small value,
			// which then gets rounded to 0.
			if (width == 0 || height == 0)
					return;

			// If color is an object then allow for complex fills.
			if (color !== null) {
					if (color is uint) {
					g.beginFill(uint(color), Number(alpha));
				} else if (color is Array) {
					var alphas:Array = alpha is Array ?
						alpha as Array :
						[ alpha, alpha ];
						if (!gradientRatios)
						gradientRatios = [ 0, 0xFF ];
						g.beginGradientFill(gradientType,
						color as Array, alphas,
						gradientRatios, gradientMatrix);
				}
			}
			var ellipseSize:Number;
			// Stroke the rectangle.
			if (!cornerRadius){
				g.drawRect(x, y, width, height);
			} else if (cornerRadius is Number) {
				ellipseSize = Number(cornerRadius);
				var squareTopLeft:Boolean = this.getStyle('squareTopLeft') as Boolean;
				var topLeftCornerRadius:Number = (squareTopLeft)? 0 : ellipseSize;
				g.drawRoundRectComplex(x, y, width, height, topLeftCornerRadius, ellipseSize, ellipseSize, ellipseSize);
			}
			// Carve a rectangular hole out of the middle of the rounded rect.
			if (hole){
				var holeR:Object = hole.r;
				if (holeR is Number)
				{
					ellipseSize = Number(holeR) * 2;
					g.drawRoundRect(hole.x, hole.y, hole.w, hole.h,
						ellipseSize, ellipseSize);
				} else {
					GraphicsUtil.drawRoundRectComplex(g,
						hole.x, hole.y, hole.w, hole.h,
						holeR.tl, holeR.tr, holeR.bl, holeR.br);
				}
			}
			if (color !== null)
				g.endFill();
		}
	}
}

Seems like a lot of work to do just to avoid a little sliver in your UI.

Hope this helps!

An Alagad Introduction

I’m a bit late on getting a blog entry up introducing myself here. Being busy is good, but it makes it hard to set aside time, even when you know you should! To anyone who doesn’t know me: Hi, I’m Brian Kotek. Like my friend Ray Camden, I’ve joined up with Alagad for some contracting work in addition to my continued work with Broadchoice. While I love what I’m doing over at Broadchoice, I’m also excited to tackle some new and different challenges.

My work on the Broadchoice Workspace AIR application has kept me pretty firmly in the Flex and Groovy world for many months. I’m happy to say that the focus here at Alagad will allow me to delve back into the ColdFusion world with more regularity. Specifically, I’ll probably be blogging on the topics of software architecture and on leveraging a Groovy-based model with CF controllers and views. There’s some pretty cool stuff happening in this area and I’m lucky enough to have the chance to leverage my knowledge in that area on some Alagad projects.

The team that Doug has put together is top-notch, and it’s an honor to be able to count myself among the Alagadians (better trademark that, Doug!) Look for more in the coming days and weeks, but for now, it’s back to the trenches.

Introductions

Hello, My name is Matt and this is my story:

I was born in New Orleans, Louisiana but spent the majority of my formative years in a city in northern Alabama called Huntsville. Huntsville is the home of the US Space and Rocket Center and Space Camp. I spent the majority of my youth running, thinking about running or selling running shoes.

I went to the University of Richmond in Virginia where I studied Business Administration and Sports Administration. I headed back south for graduate school at the University of Alabama where I earned a Masters and Marketing and was able to finish out my NCAA eligibility.

I started building websites towards the end of graduate school largely revolving around our successful track and field program and other running related news. I quickly became a Macromedia fan boy and relied largely on Dreamweaver Fireworks, and Flash MX.

After a brief stint in Europe, where I started dating my future wife, I landed a job working with the Olympic marathon trials where I was in charge of elite athlete coordination and assigned the task of building the website (Flash/PHP). After the trials I moved north to East Lansing, Michigan where my wife started attending medical school at Michigan State.

I continued to work in web development and gravitated towards application development. I tried hard to use Macromedia Flash as a front end to drive database driven software with varying success. I wrote an inventory management system for a large athletic store that is still in production and eventually took a job with a web development firm named Artemis Solutions.

At Artemis I worked as a project manager, sales consultant and occasionally was given the opportunity to do development work. In 2005 I started dabbling with a Macromedia Flex. I started spending more and more of my free time writing Flex applications and eventually took a job with Cynergy Systems.

At Cynergy I was able to work as a Flex developer on some really large and exciting business applications. We worked with a plethora of back-end service languages and I was exposed to a number of extremely challenging development scenarios.

In the past two years I’ve been playing with Java, Objective C, Ruby on Rails, and I’ve spent a fair amount of time exploring multi-touch application development. I’ve enjoyed messing with the hardware challenges and I’m a regular contributer to the Natural User Interface’s community.

We recently moved to the greater Portland area, where my wife took a job at a local hospital. We’re both enjoying the Pacific Northwest weather and particularly enjoy the large amount of area running trails.

When away from the LCD, I enjoy running with my dog Dorito, rock climbing with my wife and I’ve recently joined a table tennis club, local area running club and the PDXRIA Adobe user group.

I’m excited to be joining the Alagad team. I am impressed with the list of rock star developers that Doug has been putting together and I’m eager to learn from and contribute to this talented team of software engineers.

Hi from a Jedi, and a stupid Model-Glue mistake

Well, yesterday Doug announced the news that I’d be helping them out part time as a contractor. I’m pretty excited about this as I feel like Alagad has one of the best teams out there in the world. Not only technically, but they are just darn good people at that. So I’m happy to be helping them out in some small way and especially pleased to work with Alagadians. (Speaking of which – when do I get my shirt?) I’m still plugging away hard at Broadchoice as well, so, let me just say I’m more than a bit booked. But the good thing about a lot of work is that it tends to generate a lot of good blogging ideas.

As an example, I can share with you this mistake that my friend, um, Bob, made when working on a Model-Glue application. I would never do anything this stupid, but it felt like that kind of thing others may do so I thought it made sense to share it with the world.

“Bob” had just added a new event to his Model-Glue.xml file. He fired off a call to a controller method that should have added some data to his view state. In order to keep it simple, here is an example using a view argument to demonstrate:

<event-handler name="page.test">
    <broadcasts/>
    <results>
        <result do="view.template"/>
    </results>
    <views>
        <include name="body" template="dspTest.cfm">
            <argument name="foo" value="lando"/>
        </include>
    </views>
</event-handler>

Notice the foo argument with lando value. In my view I then did:

<cfdump var="#viewState.getAll()#">

But for some reason, the foo value wasn’t there! I – sorry – Bob – spent a good half an hour reloading, restarting ColdFusion, etc, no luck.

Turns out the issue was simple. Duplicate events. Bob had defined two events named page.test. Model-Glue didn’t throw any error, it simply ignored the first event. I did a quick bit of testing to confirm that. I created 3 events, all with the same name, all using an argument named foo, and whichever event ran last seemed to win. Under Model-Glue 3 it worked the same as well. Can anyone think of a good reason why this would be allowed? Maybe an error should be thrown on startup?

Tag Cloud