Autosave comes to blogs

Company Blogs May 20, 2008 By Nate Cavanaugh

This is a feature I know many of us have been desperately wanting for quite a while. In fact, it's something that many of us miss from other blogging apps, and we now have it.

So, to kind of show off what we have, I'll include screenshots from this very blogging session.
Isn't this awesome?!

Notice the time? Every ten seconds, we automatically save your draft until you click publish. This means that if your browser locks up (thanks a ton, Firefox 3 b5), or your whole system wonks out (*cough*Vista*cough*) you'll be assured that you'll have an up to date copy of your blog entry waiting for you to go back to it.

You know what else is great about it? Let's say you go back to your draft, and you decide the title isn't right, it automatically updates the friendly URL for you as well.

Is that more bang for your buck or what?

Now what happens if you go to see your blogs, how do you know which ones are your drafts? Wonder no longer. Take a look:

Man, Nate is one snazzy UI designer ;)

See how it has a grey box around it with the dark grey text and the icon? That's how you know it's not published yet.

We're contemplating a few ways to mark it as a draft manually, but we shall see.

Another question that might come up, what happens if you're editing an already published blog entry, does it autosave that? No. Mainly because of the big issue of let's say you accidentally type something up that the world wasn't meant to see, you definitely wouldn't want the world to see it, let alone see it in a state of flux. Or if you go in and edit, and accidentally delete everything you wrote, you sure wouldn't want that autosaved.

We have so much awesome stuff coming down the pipe, but I don't want to mention it just yet. But let's just say that I think it will just solidify even more why we're the number 1 open source portal.


How can jQuery help me today? pt. 1

Company Blogs April 24, 2008 By Nate Cavanaugh

So, when we adopted jQuery, I think I should have done more to evangelize it within Liferay. For most web developers in the world, it's really taken off in popularity because the concept is tied to an existing development paradigm, eg. CSS.

However, that doesn't mean everyone in Liferay is familiar with CSS. But the benefit for the backend folks is that it let's you focus on only having to learn one set of selectors based on an existing and widely supported standard, rather than having to relearn a whole new language paradigm.

So first things first, I'll do a quick lay of the land with jQuery that will help you get up to speed, and then I'll launch into examples that can show you some useful tips that can help you get stuff done today.

First, the concept behind jQuery is that you operate on the DOM (the structure that represents HTML elements on the page).
In normal Javascript development you do everything on the DOM elements directly.
For example:
document.getElementById('banner').style.display = 'none';
document.getElementsByTagName('body')[0].className += ' classic';

Those snippets there find the elements in the DOM, and modify their properties directly. Now, there are a lot of ways to do things like this, and honestly, a lot of them get confusing really quickly. For instance, if you want to change an attribute on an element, some people set the property directly, some people use setAttribute(attr), etc. And every browser has quirks related to this.

So the purpose behind jQuery is to "query" the DOM, and return you back a set of elements (even if its only one element) and operate on that collection.

You can think of every jQuery object as a bucket of DOM elements, and every jQuery method you do on that object is automatically done on every element in the bucket.

One thing commonly done in web dev is to get all elements that match some criteria (querying the DOM), and often, you want to grab everything with a certain class name.

In CSS you would do it like so:
.liferay-element {}

In normal JS you would do it like this:

var allElements = document.getElementsByTagName('*');
var matchedElements = [];
for (var i=0; i < allElements.length; i++) {
    var el = allElements[i];
    if (el.className.indexOf('liferay-element') > -1) {
        matchedElements[i] = el;

And then you would have your collection of matched elements.

So how would you do this in jQuery?

var matchedElements = jQuery('.liferay-element');

Looks pretty familiar, right?

So now that we have matched elements, what could we do with this? A whole ton of good stuff.

Let's say we wanted to fire an alert box when we click on each of those elements, how would we do it?{
    alert('you clicked me!');

Or what about adding another class to each element?


Or wait, let's say that we have a collection, and we want to make all of them have a red border, BUT, if the element is a span, we want a blue border?

matchedElements.css('border', '1px solid #f00');
matchedElements.filter('a').css('border-color', '#00c');

Notice the filter portion? The filter method reduces a current collection down to a smaller set based on a jQuery selector (or other things, but you can look at the documentation [] for more info).

So you may be saying "Okay Nate, that's great and all, but you're really boring me here. I don't want to add ugly borders to my elements, and I don't want to hear you ever say that easy-peasy line again, I want to DO STUFF!".

So let's do stuff.

One common thing that we've all done numerous times is use a checkbox to select all checkboxes in a set, sort of a select/deselect all option.

So let's assume we have a group of checkboxes, that don't have a classname, don't have an id, and don't have the same name.
But we know the name attrbiute all starts with the same thing, in this case:
"<portlet:namespace />check"

So, we have our checkbox that acts as the trigger, and but it doesn't start with the same name.

Our example HTML would be this:

<input type="checkbox" id="<portlet: namespace />trigger" />
<input type="checkbox" name="<portlet: namespace />check1" />
<input type="checkbox" name="<portlet: namespace />check2" />
<input type="checkbox" name="<portlet: namespace />check3" />
<input type="checkbox" name="<portlet: namespace />check4" />

Here is how we would toggle all of the checkboxes in jQuery:

var trigger = jQuery('#<portlet:namespace />trigger');
        jQuery('[@name^=<portlet:namespace />check]').attr('checked', this.checked);

So let's go by that, line by line, so we know what we're doing:

var trigger = jQuery('#<portlet:namespace />trigger');

The # sign in CSS signifies an ID, so in this case, we're getting an element by it's ID.

We're now assigning a click event to our trigger. The events that we add need a function passed in, and the function that is passed in has two special things about it, 1 is that the argument it gets is the event object. I won't go into detail here about what the event object has on it, but it let's you do all kinds of things.
2, however, is that the scope of the function is changed a bit so that "this" points to the element that you're working with. So in this case, this points to the DOM element of our trigger.

As mentioned above, here is the start of our function, with the event parameter.

And here is where the magic happens:

jQuery('[@name^=<portlet:namespace />check]').attr('checked', this.checked);

That's kinda nuts right?

Well, jQuery lets you query objects based on parameters, and you can also do minor regular expressions in it. CSS also allows you to do this (in every browser, of course, except IE 6).
It's not a direct port of CSS in this case, but of xpath, in that you have to use the @ sign. The newer versions of jQuery don't require the @ sign, but in Liferay pre-5.1, we have to use the @ sign.

So I'll break this line up:

jQuery('[@name^=<portlet:namespace />check]')

Find every element whose name attribute begins with <portlet:namespace />check. The begins with is done by this part:
if we wanted to say every element whos name ENDS with, we would do:

.attr('checked', this.checked)
This sets the checked attribute of every element we found to whatever the checked state is of the current element.
So if the current element's checked attribute is set to false (unchecked) all these elements will be unchecked. If it is checked, so will all of those elements.

Okay, but if you ask me, that's kind of a lame example. That's something we've been doing since time immemorial(like since 1999 when Ben Franklin gathered all the animals on the Ark and crossed the Delaware river), and while it's fast, it's not like everyone is screaming "HELP ME CHECK LITTLE BOXES!"

But what if we wanted to do an ajax call on a page that updated a div with the results and show a loading animation so the user isn't wondering what's going on?
Well first, we need to make sure the URL that returning the HTML we need.
Secondly, let's assume the div we want to update has an id of portletBox, and the link we're clicking points to the URL resource, and has an ID of linkTrigger.

Here's our HTML:

<div id="portletBox">
    Existing Text is here....

<a href="" id="linkTrigger">Click me to update our text</a>.

Here's how we'd do it:

var linkTrigger = jQuery('#linkTrigger');
var updateDiv = jQuery('#portletBox');
    function(event) {
        updateDiv.html('<div class="loading-animation"></div>').load(this.href);
        return false;

Let's go down a bit at a time:

This of course grabs our elements to work with.

var linkTrigger = jQuery('#linkTrigger');
var updateDiv = jQuery('#portletBox');

Now we'll add a click handler

This is where we do our work
updateDiv.html('<div class="loading-animation"></div>').load(this.href);
return false;

Let's analyze this a tiny bit. When we click the link, we're first grabbing updateDiv and replacing all of it's HTML with a div that handles the loading-animation.
Right on the end of it, we're doing .load(this.href), which performs an AJAX call and updates the jQuery elements with the results of the AJAX call.

Lastly, we have "return false;". What does this do exactly?
Well, in every browser event, there is a default action. In the case of a link, the browsers default action is to follow the link. However, in our case, we don't want to follow that link, but instead stay on the current page.
When you return false, it prevents the default action from ever taking place.

This also works with every event, for instance, with forms, if you want to do some stuff when you submit the browser, but want to prevent the actual form from submitting, you would return false.

So, that about does it for right now. I'm going to think up some more (useful) examples of things jQuery can do to make your development life a lot easier.

Is there anything you'd like me to cover, for instance, doing animations, or manipulating html elements, etc?


Company Blogs April 10, 2008 By Nate Cavanaugh

Hey there, O faithful reader...
Man, what a long time since actually posting. Since I last posted, quite a lot has happened, and included in that was the fact that my wife and I visited China with Brian and Caris, Bryan Cheung, Alice, and Dave, to go spend time with Mark, Ivan, and Shepherd.

What an experience! There are a few times in everyones life when travel truly changes you in ways you were completely not expecting.
The China trip was one of those times.

To begin with, nothing really changed my view of flying during this trip. Except maybe that I need a height-ectomy. Flights both ways were pretty much par for the course of my normal flight experiences: painful.

But the actual trip more than made up for it. I will also say that the pleasure of this trip is completely due to the grace of the people we were visiting with. Had Jessica and I gone by ourselves, we no doubt would have come back with a vastly different experience.
We were made to feel completely at home, and even though our Mandarin is limited to Ni hao and Xie Xie (Hello and Thank you), we were able to get by because of the patience of the people we were with, and the patience of the Chinese :)

The first day, I will say, was really rough. We landed with too little sleep, and the city was very overwhelming at first. Luckily though, we fell into sync with the local timezone the night we got there, and were not jet lagged at all. Jan--March2008 072

This was also the very first time in my life that I've traveled internationally and did not get sick, and that is quite a big deal to me :)

I got to me a lot of really great guys, and I will always remember Steven, Gavin, Sai, and Dale because their patience with the language barrier, and their hard work learning the Liferay theming system. They were incredibly friendly, and I do miss being out there.

Surprisingly, I don't think my comfort level was stretched too far. More than anything, I was really curious about things, but the odd thing was that while I thought the whole personal space thing would cause me grief, it's strange how oddly liberating it is to be squashed in a moving metal can with other people and have no concept of moving your arms, let alone "personal space".
The food there was quite good. Some things, not so much, but for the most part, most everything I tried, I really enjoyed (of course, the same is said when I eat anywhere, which suggests I'm not so much a worldly foodie, but more just a person who likes eating).
Of course, eating at a Chinese McDonalds and Pizza Hut were actually pretty strange.
The food outside of the chains were where the best food was found, though. Dumplings, wontons, and the normal Chinese fare we're all so familiar with was there, but so was live sashimi (where they cut off the flesh of the fish and leave it there on the plate moving its mouth...), chicken-head-kabobs, and all sorts of different and exciting items.
Jan--March2008 030
I DID manage to get my Diet Coke fix. It was glorious.
However, the first day went a bit rough in getting it, but due to the persistence of our friends, we did manage to complete the quest, as you can see below. The first machine I tried took my money, but wouldn't give me the Diet Coke. I had to settle for a freakin Fanta! But we would prevail:

Also, our office there is freaking AWESOME. I don't envy the internet speeds, but the office is so nice.
dalian, China Mar08 042
dalian, China Mar08 051
I could go on and on with vivid detail, and I might in future posts, but I will say that I learned some really amazing things while I was there.

One is that how I think I am coming across to people is often very different than how I actually am. I learned that when I interact with people, a lazy tongue and an eager ear go further than they're often given credit for.

I also learned that the people I am lucky enough to not only call co-workers, but friends, are insanely patient, loving, and kind, which humbles me that they deign to consider me a friend as well.
DSC01290 (2)
Lastly, I learned that my wife is much more adventurous and patient than I really knew, and I'm not only glad she got to go for this trip, but just overall incredibly grateful for the opportunity to experience it.
Jan--March2008 027

Random theme related tips

Company Blogs February 11, 2008 By Nate Cavanaugh

People seemed to like the "hey buddy, want to hear a secret?" nature of my last post, and in that tradition, I will try to drop some tips about some of the lesser known ways of playing around with the Liferay themes.

Browser Selectors
In Liferay since 4.3, we've used a method of browser detection called Browser Selectors. What this does is allows you to style your theme for different browsers, different operating systems, and whether or not the users have javascript on or not.

This allows you to style for not only a certain browser, but also a certain browser version.

The selector class always exists on the html tag, which means that the browser metadata used in the class name will always be first in the selector chain.
For example:

.js #navigation{}
This styles the navigation element only if the user has javascript turned on.

.ie #navigation{}
This would style the navigation element only if the user is using (any version of) Internet Explorer.


.win.firefox2 #navigation{}
This would style the navigation element only if the user is using windows, and Firefox version 2.

This is much cleaner than using hacks in your css to target a browser.
Mind you, these will only work if the user has Javascript turned on.

Turning off portlet title editing
Sometimes you don't want your theme to have editable titles (you know when you click on a title and the admin user can edit the name?)

The way to do this is to open up your portlet.vm in your theme's templates/ directory, and add this class name "not-editable"

So the HTML would look something like this:
<span class="portlet-title not-editable">

Turning off dragging and dropping of navigation, and turning off the Add Pages functionality
Sometimes you don't want this added functionality. It's great sometimes, but sometimes, it can be a pain. There are two classes that exist on the navigation div that control this functionality.
These classes are sort-pages and modify-pages.

"sort-pages" adds the ability to drag and drop your navigation elements, and if you remove this class, you'll be able to add new pages on the fly, but you won't be able to sort them.
"modify-pages" adds the ability to edit the page's title, and adds the "Add Page" button to the navigation as well.

Turning off the Drop Down dock
Sometimes, you don't want the interactive dock that drops down with a list of actions. In the Classic theme, for instance, you can have it display as a friendly horizontal list of icons and text. To do this, just open up dock.vm and remove the class of "interactive-mode" from the dock div.

I think that's about it for now. I'll try to blog a few more as they come to me, but overall, this might/should/maybe help out some people who have been curious :)

Hooking into Liferay's Javascript functions

Company Blogs February 4, 2008 By Nate Cavanaugh

Have you ever wanted to plugin to Liferay's javascript functions, but didn't want to modify the original Javascript, and didn't want to branch off of it? I know I have.

For instance, let's say that there is a Liferay javascript function that always adds a class, but you don't want to add that class, and instead want to use your own. Well, there is a little known method that does this that's in Liferay 4.3.x.

The method is called Liferay.Util.actsAsAspect. This little method adds AOP (aspect oriented programming) features, that allow you to hook into existing Javascript without a plugin framework being in place.

So, I'll use a good example of this. In Liferay, if you don't want the dock to be a drop down, you can go into dock.vm in your theme, and remove the class name of interactive-mode off of the main dock container.
This allows you to easily disable that feature.
But recently, we needed to remove this class, but didn't want to keep a floating copy of dock.vm where the only difference is one little class name.

So we could either modify the file anyways, or we could use Javascript to remove the class name. But then there become a race condition, where you're trying to race against the Dock javascript to remove the class before it can find the class and begin the transformation.

Well, that's where Liferay.Util.actsAsAspect comes in.

What it does is it takes the object you pass to it, and augments it to contain three new methods: before, after, and around.

So, in our case, we needed to modify Liferay.Dock (the class that creates the dock), and we needed a way to guarantee that the class name interactive-mode was removed, thereby preventing the Dock class from even seeing that there is a dock to modify.

So, here is what we did:



So, you see, now every time Liferay.Dock.init() runs, it will always execute our little function we passed into it first.

We can also run Javascript after, using Liferay.Dock.after() and passing in the name of our method, and a function we wish to execute.

We can also wrap the init function with code, like so:

function () {
    var dock = jQuery('.interactive-mode');
    this.yield(); // This line executes the original function
    dock.addClass('interactive-mode'); // This line now adds the class back after the function fires

Now, the next question you may be asking is, how do you do this for classically defined functions (you know the ones that look something like: onLoad() or _88_updatePage()), and don't have a parent object that we can manipulate.

Well, we actually can manipulate because all functions defined like this: function _88_updatePage() {}, all exist inside of the "window" object. The "window" object is the global namespace where normal functions are added by default.

So, here is how we would execute a function before _88_updatePage get's executed:


function (month, day, year){
    alert('I am just about to update the page');

So, anyways, I thought that this would be helpful to people who need to hook into our existing Javascript, and can't wait till we implement our formal JS event system :)

New Liferay Desktop Theme

Company Blogs January 25, 2008 By Nate Cavanaugh

A few months ago, Peter "The Man" Shin started working on a new theme for Liferay, called, appropriately enough, Desktop.

Yes, I know we already had a theme called Desktop, but to be honest, it wasn't the greatest theme in the world. The different "OS's" was actually just different backgrounds on the same theme.
So, to the rescue, Peter went through and created a new theme, with 3 real OS versions included in it, which I've shown below.

If you get a chance, tell Peter how much the theme rocks by emailing him at "P shin @ liferay [dot] com" (use your mental regex engine to parse that one out :) ).

How do you get the theme? Download the latest bundle of Liferay (4.4.0), and go to your Plugins page, which is located in the Welcome dock > My Places > My Community > Private Pages. Click on the Theme Plugins tab, and you should see the Desktop theme.

Click on the link, and press the Install button, and you're all set.

I'll be blogging on the best way to do this soon, so users can see what the process looks like.

Click on a thumbnail to see the theme in full size:



Mac OS X


Ahh, the travails of travel

Company Blogs January 15, 2008 By Nate Cavanaugh

I don't know how Bryan Cheung does it. I believe he flew over 100,000 miles last year, and I'm really quite surprised he's still sane.
Why do I say that? Because if any of his trips are anything like the one I am currently on, then I have to give him some sympathy and a newfound respect.

Right now I am in Frankfurt Germany with Mike Young (who actually had to take a train to Paris last night), and so far this trip has been a bit of a comedy of errors for me.

I am loathe to complain, because this is all stuff that can and has happened to anyone, so I don't think I'm a martyr for it happening, but it has been a pretty rough ride so far.

How it starts

It all started Wednesday night, when Amazon emailed me to let me know that my Kindle (I got one for Christmas, ordered it December 2nd, but have been waiting forever to even get an approximate ship date) would arrive for me THE DAY AFTER I left. A small thing, but if anyone knows me, they know I've had an unhealthy obsession with getting one.

Thursday morning, the day of our flight, I wake up to find out that some plumbing problem in our apartment building had flooded our toilet and shower (hopefully with different water ;) ), and I wouldn't be able to use the bathroom or take a shower. I called Mike and he said it was okay that I take a shower at his place.
But, alas, in the rush that ensued after that, I forgot a camera for the trip, AND my international converters. Power might be nice, considering 99.9998% of my work is done on one of those fancy computers the kids rave about these days.

I get to Mike's, and I'm able to take a shower, and we head to the airport. About 40 minutes into the drive I realize I forgot my jacket.
Not good news considering that it's about 30-40 degrees Fahrenheit where we're going. But, I remind myself that I packed a sweatshirt, long sleeve shirts and plenty of thermals, so I should be fine.
Oh boy, was I naive.

The plane ride

We get to the airport and our plane is delayed, so they move us to another flight leaving about a half an hour earlier so we won't miss our connection.

I'm 6'4, so flying in economy is rather painful for me, as it inevitably means that my knees are next to someones ears, or they're spread out into the aisle so that the Panzer that they've converted into a drink cart slams into my knees.

Thankfully the first flight was pretty short, only about 2 hours. But the second flight, on a beautiful Lufthansa plane, was a ride, let me tell you.

The lady in front of me decided she wanted to sleep the entire way. I don't blame her. Except that she was like 5'4 and the seats were made just right for her.
So she reclines her seat so far back that it literally forced my knees into the aisle, and her headrest was about 3 inches from my forehead. I actually heard her stretch and yawn to the guy next to her "Life is great". For you, lady, but the giant, lumbering white guy behind you is getting his legs amputated.

I should have just asked her not to lean so far back, but on a 10 hour plane ride, I needed something to do in between chapters of my book, so after the meal was served, and she tried leaning back again, I just used my hand to hold her seat up. She kept trying for what seemed like 30 minutes, at random times. Over the next couple of hours she tried slamming the seat back, but by now I was having fun with this ridiculous passive aggressive game of "What's stronger, her back or my arm?".

I do regret not just asking her to stop leaning back so far, but at least I have a somewhat humorous lesson to share with people who believe that leaning back in their airplane seat affects nobody else.

After we land, we decide go to baggage claim, and fairly quickly, Mikes bag comes. I wait for mine, as he goes out to meet Paul Bakaus, who's picking us up.

But, guess what? They lost my bag. Yep, the bag I packed with Paul's laptop that we're delivering to him. The bag with my thermals and sweater, and fresh clean clothes.

So I go to baggage claim, but because Mike checked both bags in his name, and he's not with me, there's only so much they can do. They try paging Mike and Paul, but they didn't hear it. So I go out to the main area and try to find them both. I page both Mike and Paul again, and again they didn't hear it.
So after searching for 20 minutes, I finally find them, we go back in, give them the appropriate numbers, and they tell me they'll keep doing a search, and deliver it when they find it.
Thank God Paul was able to take delivery of it to his place.

Thank you, Netherlands

Mike and I planned to take a quick weekend trip to Amsterdam to do some sight seeing, so we board our train, and get into Amsterdam around 6pm.

We eat dinner and mill around. Frankly, it's freezing cold. All I have is a tshirt and jeans on, and I am hurting.

The next day we make it to C&A which is like some European Kohls, and I was able to pick up a jacket, a pair of jeans, some more shirts, some socks and such, and for a fairly reasonable price.

We decide to rent some bikes and tour around Amsterdam, and check out a cheese farm where they make, you guessed it, cheese but also clogs.

We ride back, and go out to dinner again later that night (which was a really delicious Indonesian place). We head back to the hotel and go to sleep.

At about 4am I wake up freezing cold, and having massive chills. This is a strangely familiar feeling, considering that just a few weeks ago I recovered from the flu.
And now, I have it again.

For the past 2 days I've had a really bad fever and have been struggling to even move out of the bed. And even though I've been taking sleeping aids, I can't stay asleep for more than 4 hours.

So, I'm sick, jetlagged, and dressed like a homeless person.

Luckily, though, I think the fever finally broke last night. I didn't wake up in chills (just drenched in sweat), and I'm beginning to feel a bit better.

The point. There is one, and I got it

Thankfully, though, God has used this time to teach me some valuable lessons.

For one, that He will provide for all my NEEDS. During this entire time, all of my basic needs were met.
Another lesson was exactly how few my needs are. A lot of times I get hung up on the creature comforts of life, and I forget just how little I actually need.

Another lesson I learned was from a verse that I haven't read in a while. It's from Proverbs 3:11 & 12:
"My son, do not reject the discipline of the LORD
Or loathe His reproof,
For whom the LORD loves He reproves,
Even as a father corrects the son in whom he delights."

Many times (and I should probably say MOST of the time) I do resent it when my life doesn't go quite as I had planned it.
I need to change that.

One other thing that has really hit me again and again while being at Liferay, and that is just how small my problems in life really are, especially compared to the leadership in the company.
Business is tiring, stressful, hectic, and demanding. Those of us who don't carry the daily burden of billing, cashflow, HR, employee management, client relationship management, etc, are spared the daily anxiety of dealing with it. But somebody does deal with all of those things.
And while I was able to get my luggage back, and my flu will go away, and plane seats will one day become comfortable, the painful struggle of pioneering a company with 60 people dependent on you is tough.
So my griping comes with the understanding that it's rather mild in comparison to other's real struggles.

I also learned I am incredibly blessed to even be in the position that I am. Yes, I miss my wife desperately, yes I feel like the devil kicked me in the gonads, and yes, I probably stink like the Los Angeles "river", but in the end, here I am in my fourth European city since joining Liferay, working at a company with and for people so insanely talented that it makes me giddy, and with a life thankfully rich with a wonderful, if somewhat fractured, family, rich in quality friendships, and overall, I am quite content with my life.

The other lesson I've learned, and Mike actually came up with this, and it would be to have the option to be tranquilized on long flights and placed in a tube, a la the Japanese capsule hotels I used to watch about on "That's Incredible!".
You would get a shot, be placed in the tube, and wake up in 12-15 hours later in your city of choice.
Maybe they wake you up half way through so you can avoid the DVT's, and maybe use the restroom.

I don't know about you, but I'd be up for it :)

OS X and Liferay tip

Company Blogs December 30, 2007 By Nate Cavanaugh

It's been exactly 10 years since I got my very first computer, which was on Christmas of '97, and was a $400 dollar IBM clone, running Windows  95. I didn't even know how to change my wallpaper, or use my computer for anything more than a CD player/Calculator/Solitaire machine.

It's odd that exactly 10 years after getting my first computer, I am reaching another first, and that is my first Mac.

I have made the switch, and I am sold.

There has been some small issues, like a lack of decent freeware, and a few little oddities, but overall, it's been incredibly pleasent.

One of the things I love is the fact that it's based on FreeBSD, and it means I have a file system that actually closely mirrors the web servers I've been used to developing on.

But one thing I missed from Windows was shortcuts to my different Liferay installations. Clicking on startup.bat would load a new command propmpt window, which would show the log in that window.
Unfortunately, in OS X, when you run from the command line, it doesn't do that. Basically, the normal workflow is:
Navigation to your Tomcat/bin directory
run tail -f ../logs/catalina.out

Kind of a pain, if you ask me. Brian Chan also taught me that you can shorten that a bit by just using './ run', however, I think this could be improved a bit too.

So, what I did was created an alias called liferay that runs that does just that. This way, I can just run the command from anywhere, and it will launch Liferay right there, and show the catalina.out log.

Of course, there could be better ways to do this, and I would love to hear them. I am a relative n00b on the Mac, so I am sure there will be some cool optimizations and the like that I won't get.

So here's how you can quickly create the alias:

  1. Open Terminal
  2. Type 'pico .bash_profile'
  3. If there's anything in the file that opens up place the following line at the end, if not, just place it at the first line:
    alias liferay='~/Desktop/Development/Tomcat/bin/ run'
  4. Replace the path above with the path to your tomcat directory.
  5. Press Ctrl X, and then hit Y when it asks you if you want to save, then press enter
  6. At the command line, type 'source .bash_profile' to refresh your profile
  7. Type liferay to launch Liferay from the command line.

Now, you can always just use the liferay command, and just press Ctrl C to exit out.

I will be playing with some ways to manage a bunch of different bundles and be able to launch them easily without having to navigate the file system via CLI everytime I need to launch one.


CSS Inheritance

Company Blogs December 14, 2007 By Nate Cavanaugh

So yes, there has been a long delay from the last time I blogged, but I thought I would come back with something that I have actually been asked a lot about recently, which is CSS Inheritance.

I'm finding out that front end technologies are like Sanskrit to many server side developers, which is strange, because CSS and Javascript, to me, are easier to understand.

But issues like inheritance in CSS (and OOP in Javascript) break convention so much that it's hard carrying over knowledge of the server side to the front end.

Many people assume that inheritance is controlled by a few factors, one of them being source order. And, it's true, that all things being equal, the last line of code in the source takes precedence.

But that's assuming all things are equal, which, as we'll see, is not often the case.

Let's take a look. Assuming that we have a body tag like this: <body class="my-class">, and this CSS in our file: { background: #000; }
.my-class { background: #f00; }

What color will the background be? Most people might assume that it's #f00 (red). But alas, it is not.

The background color of the body would be black (#000). Why? Because of one of the more confusing (but powerful) features of CSS, and that is CSS Specificity.

The idea behind it is that the more specific your selector, the more precedence it's going to have.

So what about a code setup like this:

<body class="my-class" id="myId">

and CSS like so:

#myId { background: #000; }
html > { background: #f00; }

Again, the body background color would be black. Confused yet?

The reason is because each piece of the selector has a given weight, but they're not all equal. Each selector is actually a calculation of it's pieces weight, so that every selector has a certain number of points.

This is news to most people, but it's true. Each selector has browser given weight to it, and if you add the points up, you can tell which selector will win out.
So what are the points?

Elements (li, p, a, table, etc) all have 1 point.
Classes (.my-class, .banner, etc) all have 10 points.
Psuedo classes and attribute selectors (:link, :hover, :focus, [rel=external], [type=text]) all have 10 points
ID's (#myId, #wrapper, etc) all have 100 points
Inline styles (style="background: #0c0;") all have 1000 points.

So if you want to calculate why a certain style isn't getting applied, some quick math, you would see that a setup like this:

a[rel=external].my-class { background: #f00; } { background: #0c0; }

Would result in a red background (#f00) because of the points.
In the first selector we get 1 point for a, 10 points for [rel=external], and 10 points for .my-class for a total of 21 points.
In the second selector, we get 1 point for a, and 10 points for .my-class, so 11 points for that selector.

But, the confusion doesn't end there. There are some caveats.
For instance, an ID, even though only containing 100 points, will win out even over a selector with a point value greater than 100 points.

So an ID always has precendence over all other selectors, except if there is another ID in that selector. And an inline style will always win out over an ID, even if there is a 100 id's in the selector.

Now, to pile on the confusion even more, you can give weight toa certain property that will always be obeyed, no matter where the  selector is defined.
You would do that with !important.

Here's how it would work:
body { background: #fff !important; }
body#myId { background: #f00; }

The body would get a background color of #fff, even if there is an inline style, or some other heavy selector. 2 caveats, however.

1. This doesn't work in IE 6.
2. This can cause problems in styling and should only be used in rare cases.

Personally, it's stuff like CSS specificity and inheritance that cause confusion, and keep people from using the full power of CSS to their advantage.



The Amazon Kindle.

Company Blogs November 19, 2007 By Nate Cavanaugh

All I have to say is wow. Pure, unadulterated WOW.

I have been waiting for the iPod of books to reach us, and I truly thought it would be either Sony's Librie, or more likely Apple.

But it turns out to come from who now seems to be the most obvious supplier, but the one you would least suspect, and that's Amazon, the book people. This has seriously given me a level of excitement that I haven't known since I first got an iPod. Only I bet this will be much more valuable to me.

In case you haven't heard, the Kindle (a great name, btw, far superior to Sony's), is a digital and portable book reader.

I thought the form factor was pretty ugly until I saw it in use on their video. I am a convert.

So let's look at the features that have me drooling so far:

  1. E-ink/e-paper display:
    Sony first debuted this technology back in '04, and I've been waiting for someone to truly utilize it. It's as crisp as real ink on paper, and there's no glare in sunlight. It also doesn't get hot like normal displays.
  2. Hundreds/thousands of books on one machine:
    This will save me not only space in my house, but open up a whole new world to me, as I can take this anywhere and read books that I may be behind on, or ones I've forgotten.
  3. Free-ish Wireless access anywhere!
    By using EVDO, Amazon is allowing us users to access the Amazon store from anywhere, and download books at any time. But not only that, it allows us to keep up to date on blogs and RSS from anywhere.
    And all for free. I don't think we can surf the entire web, but for free we can keep up to date on our feeds, shop for new books, access Wikipedia (!!), and download books in under a minute. All with no fees, no charges or plans or any hassle. Thank you Amazon.
  4. Define a word from your book:
    Not sure what antidisestablishmentarianism is? Look it up from there.
  5. Search your book:
    Okay seriously, this is awesome. How many times have I just known there was a quote, a phrase, or some text in the book, but didn't remember quite where it was.
  6. Remember my place:
    This is just hot. You can also bookmark pages as well. You can highlight, clip a a page, or add a note.
    They store the books you buy online, so you always have a free backup in case the Kindle is lost or stolen.
  7. Books are cheap:
    $9.95 for new books and best sellers? This will save me hundreds of dollars a year. Unf! Most of them have samples, so you can read a bit before you buy them.

I absolutely have to have one.

There are a few downsides I can percieve, but none I can think that will discourage me from getting one.
Here they are:

  1. No color:
    E-ink, at least for now, doesn't have color, but I'm sure that's somewhere down the line. Most of the books I read don't have color anyways, so I'm not stressed about it.
  2. A bit pricey:
    At $400 bucks, it's a bit on the pricey side, but no more so than an iPod, on average.
    And so much more versatile. This gives me access to knowledge. I'll take that over access to music any day.
  3. No elitism:
    This is a good thing all around, as I see it. People will buy books because they want to read them, not so they can say to the people around them "Aren't I intelligent because I can read Umberto Eco?".
    Also, you can read your Danielle Steele novels without people laughing at you.
  4. No nightime reading:
    From what I could see, it doesn't appear that you can read in the dark with the Kindle. It does however adjust to light, so the contrast will vary for whatever is easier on the eyes.

Overall, this looks incredible.

Check out the video on the product page here.

Friday Funkfest Nov.09.2007

Company Blogs November 9, 2007 By Nate Cavanaugh

So, in an attempt to add some stuff to my blog that I think people might enjoy, I am going to write an entry every Friday, called the Friday Funkfest.

What is the Friday Funkfest, exactly? Well, one of the things I absolutely love to do is customize my Windows box with different programs, wallpapers, extensions, etc, and I love visiting really great looking sites, I thought I'd spread a little bit of the love around share some of my faves.

So, with that said, let's get started on our first Friday Funkfest...

(Gorgeous) Website of the Week

Dibusoft (

Even though this site is in Spanish (and unreadable to me), it's very tasty on the eyes. The subtle blue hues, the contrasting yellows, and the playful illustrations all work together to make a really awesome looking website.

(Useful) Website of the Week

What should I read next? (

Having been an avid reader for my entire life, I've always loved finding new stuff to read. One of the things I've always had trouble with, however, was finding a new book to read after I finish one.

This site tries to solve that problem by suggesting titles similar to the one you just read. These are based off of user contributed lists, and the site searches through people with similar tastes and compiles a list based on what you just read.

So, for instance, let's say you've just finished reading The Importance of Being Earnest by Oscar Wilde, and you want something similar to spend your time with. You would just enter in the Title (Importance of Being Earnest) and Author (Oscar Wilde), and you'd get a nice list of recommended books.

This is especially great if you're trying out a new author or genre, and discover that you really enjoy it.

Application(s) of the Week


Directory Opus (

I can't say enough about this program. It's a Windows Explorer replacement that is by far better than any other one I've found.
For one, it actually replaces the Win + E shortcut that launches Windows Explorer.
It also supports multiple panes to copy between. There are seriously WAY too many options, and configuration possibilities.
It's ~$60 but it was worth every penny.
Here are some of the features that I use on a daily basis:
*Lock step navigation between two panes (let's say I have two identical directory structures on different drives, I can load them up each in a pane, and when I drill down into a directory in one pane, the other pane goes with it)
* Multiple tabs (each pane can have unlimited tabs with different directories)
* Vista-like breadcrumb address bar
* When you go up a directory, it highlights the previously visited directory
* Built in FTP support, and saves unlimited site profiles for those FTP accounts
* One-click copy/rename between directories
* Click a file to rename it, and highlights only up to the extension (also like Vista)
* Vista-like checkbox mode (each file gets a checkbox next to it so you can select it that way)
* Middle mouse click to select multiple files/directories
* Press ctrl to automatically copy a dragged selection between directories
* New find dialog box, with support for wildcards OR regex
* Super fast built in zip compression (with support for adjusting compression levels)
* Start typing anywhere in a directory, and it will do a Firefox-like find as you type, and match the entire string (not just the first letter, which is how it is by default)

And a TON more. I really suggest you give the trial a whirl. You shall become addicted.

To balance out the paid program choice, I am going to include a freebie recommendation as well.

Texter (

Texter has literally saved me hours of work typing, hundreds of thousands of characters, and been an overall boon to me.

What's it do? Let's say you're constantly writing the same text over and over again. Most of us programmers do.
Texter lets you assign a snippet of text to almost any key combination.

I'll give you an example. In Javascript, I am constantly writing anonymous functions. Instead of always having to type out function(){} over and over, I've assigned a hotkey to the following key combination:
fun + TAB, so every time I type the word fun, and press TAB, it automatically replaces it with:
function() {

I also have this set for btw to replace it with "by the way", ttyl with "talk to you later", etc. I am constantly mispelling the to read teh so I've set up an "instant" replacement to automatically correct it for me.

I've done this with CSS properties (db+TAB prints out display: block;, pa+TAB prints out position: absolute;), etc.

It also allows you to write replacements that execute special keys, so for instance, I can write a hotkey called css that when I type css+TAB, it creates an entire new rule, like so:
.selector {
and highlights the word "selector" for me, so all I have to do is start typing the selector.

This program will rock your world. I recommend downloading it (it's open source and free).

And that is it for our first Friday Funkfest ladies and germs.

Thanks for visiting.


PNG icons in IE6

Company Blogs November 9, 2007 By Nate Cavanaugh

One of the most controversial things we've done for version 4.3 was to switch all of the icons to using PNG icons.

This wouldn't be so bad, as IE can render PNGs with index transparency just fine. The problem comes in when you use PNGs with alpha transparency.
What's the difference?

There are two types of transparency when it comes to images. Index and alpha. File formats with index transparency use only 8 bits of information. This means that for transparency, you have a lot less flexibility it transparency.
You essentially get on or off transparency. Something is either transparent, or it's not.

With alpha transparency, however, you get a wider array of options. Most alpha transparency uses 24-32bits. This means that you could have gradients, fades, and other options that you can't have with the index formats.

As I said before, the switch was pretty controversial, but not because of the file name switch (though that causes some problems, they're fairly easy to overcome), but because the default icon set in the Classic theme uses alpha transparency.

This means that people who view the site with IE6, roughly half the market as of this writing, will see a grey background behind each icon.

We tried numerous methods to get around this, even converting the icons to using index transparency. The problem with that was that it made the icons ugly for everyone, even the other 50% of the market who CAN view alpha transparency based images.

So, I recently discovered a fix that is absolutely brilliant. I have to give many thanks to the talented Rogie King who developed it.

It's pretty hacky, but it works.

As of version 4.3.5, we'll be including this fix in the base themes, and including a macro for people to use. The way you will use it in version 4.3.5 is to place this line into the style element of the head of your document inside of portal_normal.vm:


But, if you don't want to wait for version 4.3.5, here is how you would use it now. In the same place where you'd put the macro (in between style tags inside of the <head> of your portal_normal.vm) add this:

/* ---------- IE6 PNG image fix ---------- */
.ie6 img, .ie6 .png{
    azimuth: expression(
        this.pngSet?this.pngSet=true:(this.nodeName == "IMG" && this.src.toLowerCase().indexOf('.png')>-1?(this.runtimeStyle.backgroundImage = "none",
        this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.src + "', sizingMethod='image')",
        this.src = "$images_folder/spacer.png"):(this.origBg = this.origBg? this.origBg :this.currentStyle.backgroundImage.toString().replace('url("','').replace('")',''),
        this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + this.origBg + "', sizingMethod='crop')",
        this.runtimeStyle.backgroundImage = "none")),this.pngSet=true

You can also add a class of .png to any image that you'd like to apply this hack to.

Some caveats, though:

  1. This does not work on images with background positioning.
  2. This will not work on all Liferay generated elements (for instance, the tabs use background images, and rely on background positioning to work)
  3. Must exist inside of portal_normal (can't be in an external CSS style sheet)

I think this should really help the web devs amongst us. Enjoi, guys!

The AJAX Experience - Day 3

Company Blogs October 28, 2007 By Nate Cavanaugh

This post is a bit tardy only because the past couple of days have been pretty backed up, but the last day of the conference was one of the better ones.

I'll go through the sessions that I was able to see.

Keynote: Don't Make Me Click by Aza Raskin
I learned more in this one keynote than I did in all of the other sessions, combined. This talk just absolutely ruled. I truly wish that every single developer for Liferay could have been there. I want to talk briefly about what he talked about, and how I think it can apply to Liferay, and enterprise software in general.

His first question was, what's the ideal interface? He clicked to his slide, and it was a blank screen. The interface, above all, should be invisible. It should be seemless, and you shouldn't even think about it, because it's so easy to use.

His example was that of a shovel. You have the blade of the shovel, the "business logic", and you have the handle, the "interface". He mentioned how most software looks like a full size shovel with a 6" handle. All the work has been made to make the shovel the best tool, diamond encrusted, completely unbreakable, and yet people can hardly lift it.
He also showed the Microsoft version of the shovel, which was essentially a giant digging tractor that connects to the internet, answers phone calls, and does pretty much everything except really dig.

And the point that stuck out to me the most was when he asked what the user wants, and he showed a picture of a hole.
THATS what our users really want. They want the work done. The interface should be designed to get to that goal. Whether it's with a Web 2.0 style, whether it looks like 1999, getting the user to "Done" is our job.

He also talked about how the worst interface is one that is a thin veneer over it's underlying implementation.
This is why many web app UI's are really bad. It's practically just an interface to enter information into a database, rather than something that's thought about and designed to accomplish a goal.

He used Google's homepage as a good example of that, and went through and showed many different ways that Google could have screwed it up by adding more options, more form fields, and more "noise" for a user.

Later on, I met up Aza and chatted for a bit, and he's an awesome guy. I loved the keynote, and if for nothing else, I'm glad I could see his talk.

Design Patterns and Animation with jQuery by Paul Bakaus

Paul is an absolutely brilliant guy, and the content of the talk was great. I think he was a bit nervous, but overall he did a fair job.
He talked about the different ways to handle animations and the different design patterns.

It was also one of the talks where I felt like I was learning something. I was really glad I could make it.

Ajax Futures Panel and Q&A with Douglas Crockford, John Resig, and Aza Raskin
It was great to see John and Doug on the same stage finally, and letting them hammer it out between them about Javascript 2. Doug is an entertaining guy to listen to, even if I don't agree with him 100%. But he was quite even handed in talking about the new spec, or at least his openness to being wrong.

The Q&A was pretty terrible, though. They managed to find all of the people with either accents too thick to follow, people too timid to really speak above a whisper, or people who would just ramble on without ever getting to a question.

Hybrid JavaScript: Extending the Capabilities of the Browser as a Platform by Nathan Naze

Nathan did a fair job as a presenter, though I really did enjoy his talk about the different standards, the browser as a platform, and the intertwining of Flash and Javascript.

I wish he had come a bit better prepared, but that's a small gripe. He was very likable, and his content was good.

And that was the last session I was able to make it to.

I am just so happy I could have made it. This coming week I am doing on site training for one of our clients, and Thursday night I get to go home.

I think the training will go well, and I'm looking forward to helping them get rolling and productive, but I miss being in the office, working with the guys, going to get Pho and Maxim (the Chinese Denny's :), and getting cracking on fixing our other interface issues, and implementing new features, but most of all, I miss my wife, and I'm looking forward to a nice weekend of relaxation with her.

Sadly, the next Monday, I will be getting 4 cavities filled and a wisdom tooth pulled.
Yay for dentistry!

Alrighty folks, that is it for this years AJAX Experience roundup. I will now go back to blogging about design, interfaces, and the other random stuff I come up with.

Until then, I bid you adieu...

The AJAX Experience - Day 2

Company Blogs October 25, 2007 By Nate Cavanaugh

So, day 2 of the ol' AJAX Experience. Unfortunately, I wasn't able to attend many sessions today, due to having to reschedule doctors appointments, navigate the trickeries of booking hotels (which got handled very wonderfully by our very own Jen Yamamoto and the famous (and eternally patient) Caris Chan [many many thanks again to you both]), and general coding work.

I was able to check out a couple of the sessions though, and they were generally pretty good. I'll go over the talks briefly, and then just talk about random Boston stuff.

Advanced jQuery by John Resig
John did another good job with this talk, but sadly, I was hoping for more from the session. It was basically him building a social networking app from scratch, and using jQuery to handle the interaction.
It was nice to see him promote Unobtrusive Javascript (UJS) techniques, but it's not anything new or exciting.
I would have liked to see some more OO based stuff, some funky closure hackery, or even some things about custom events, and using them to enforce an observer pattern.

Advanced Web Security by Joe Walker

Joe (of DWR fame) went through and talked about some pretty hairy stuff that can happen in a web environment. He talked about the usual Cross Site Request Forgery (CSRF) and Cross Site Scripting (XSS) attacks, but he also talked about things like domain pinning, where a malicious site can set a DNS timeout of 1 second, embed an iframe after 2 seconds that points to your intranet, and the browser now thinks that the iframe and the main page are pointing to the same site, so that the malicious site now has full javascript access to your intranet. Luckily, the browsers have begun to not allow DNS timeouts of 1 second, but I can see the principle still holding.
He also showed some very cool, if somewhat non-threatening ways for a third party site to see what sites you've visited via Javascript and CSS.

Basically, the malicious site lists off on a plain page hundreds or thousands of links to various sites, and the site can use Javascript to read the current color of the links. So if the links are purple, it can tell that you've visited that site.

There were some good best practices in there, and Joe was a pretty decent speaker.

Sadly, those were the only two I was able to visit.

I did however manage to get to see an old friend, and learn about the awesome Boston subways, and visit the northend, where it's pretty much a Little Italy.

My buddy Josh McGinnis, the business & marketing director at PowWeb hosting, gave me a very nice tour. I got to go to the Cheers bar (which is actually called Bull & Finch), which consisted of walking around and walking right out. What would really be the point of ordering a Diet Coke from a bar?
We stopped by a market where I had an awesome (if somewhat cold) piece of pizza, and in honor of Mike Young, I stopped by Mikes Pastry, and got a Pignoli Macaroon, a Chocolate dipped  something or other, and some apricot pastries.
The place was packed, and Josh said it was actually slow. Usually the line runs out the door.

I am here until Thursday the 1st of November, so we will probably hang out this weekend. I am really kicking myself that I forgot my camera, though.

I can say that traveling is pretty tough, and I have a ton of empathy for our consultants. They are an incredibly vital part of our business, and boy do I appreciate the sacrifice and time they put into travelling every week, or even the long term commitments that some of our guys make, like James (BTW, James, did Suresh ever give you your passport back? ;).

I have to say, I miss my wife Jessica quite a bit, but thankfully, we both love Liferay, and when you're passionate about what your doing, 2 weeks isn't long.
Especially when 1 of those weeks is spent at a very sweet conference :)

I really feel incredibly blessed to be a part of the Liferay team, not only to get the perks of going to a conference like this, but working with a mindblowingly brilliant group of folks. I've gotten to see quite a few places that I wouldn't have gotten the chance to see otherwise, and while I would have loved to have Jessica join me, I have to say that getting to experience it at all is a true blessing.
And working with people who you not only respect, but actually like, and love spending time with is such a critical, and awesome, experience. Getting to goof off with the Br(i|y)an's and Mike, hanging out at the company BBQ's and social hours, and connecting with the people you work with in ways not even related to work is probably the biggest perk we have.
Learning from these guys, and being able to truly contribute is something I have always wanted, and am glad I've found it in Liferay.

Okay, I promise I won't start singing "We Are The World".

The AJAX Experience - Day 1

Company Blogs October 25, 2007 By Nate Cavanaugh

So, here I am at The AJAX Experience conference in Boston, MA. This is an industry event for Javascript and AJAX developers, as well as a chance for different vendors to promote their AJAX wares. Folks like AOL, Mapquest, Sun, Adobe, Google and the like are all here, along with IBM, and many other people.

There are also some AJAX/JS superstars here, like John Resig, the founder of jQuery, Alex Russel the founder of Dojo, Doug Crockford the "inventor" of JSON, along with a lot of other folks who are just as knowledgable, if not as well known.

Over the next couple of days, I am going to try and blog about the different sessions I am attending, the buzz I am hearing about, and any other minutia I may be privy too. I have already scoped out a couple of interesting sessions, and there are some more coming up.

One comment I will make before I get started on the sessions: this place is freakishly cold. And when the cold is bothering *me*, you know it must be akin to a commercial freezer.

Keynote - AJAX: Through the looking glass
by Kevin Survance, CTO of Mapquest

I thought Kevin did a pretty good job with his Keynote, and he actually hit along a lot of implementation issues and features that they've run into at Mapquest. He definitely is a comfortable speaker, however, I wish he had talked more about what they're doing to take on Google Maps. All he mentioned was the new beta of their service, but it looked like a simple Google Maps clone. Hopefully that's not all that it is for their sake.

One thing I didn't know was just how large their open source stack really is. Kevin took quite a bit of time out to thank the different open source communities, and it was actually nice to see.

The Future of Javascript by John Resig
John did an awesome job in this talk, and it was really interesting to see what's coming up in Javascript 2 and ECMAScript 4.
There are a lot of really cool features coming to Javascript, and a lot of new features that will please the Java developers among us. For instance, true classes, packages, interfaces, strong typing, and some other very cool features like block scope.

Here is something I thought was pretty cool to see:

var x : (string, int) = 5; // x can now only be either a string or an int (or null)

Now, I am a huge complainer and general rabblerouser when it comes to strongly typed languages. Personally, I feel that strongly typed languages hamper adoption, and make things way more complicated than they have to be.
However, I think that the option can be there for when it's needed.

There are however, quite a few strong opinions about this. There are a few people who are really unhappy with the implementation.
The goal is supposedly to make the language completely backwards compatible, but there is some debate on whether that's going to happen or not.

If the features I've listed above are "enforced" upon the users, then I would say they're bad ideas, but if they're options, I say great.

One of the other things Mozilla is working on is called ScreamingMonkey, which will enforce Javascript 2 to IE, if IE doesn't adopt it in their jScript implementation.

The way they're going to do this actually surprised me, considering my most recent post regarding the Flash Rendering Engine.
Basically, Adobe is going to be bundling the Tamarin javascript engine with the Flash plugin, which will give developers access to the new features of Javascript in any browser that supports Flash.
This is not only incredible news, but also makes me think I was on the right track with where I think Adobe should head.

Reaching the Entire World: Accessibility and Internationalization with Dojo with Adam Peller and Becky Gibson

This talk was somewhat dry, but incredibly important to me. It was a bit of a push for Dojo, which is understandable, given the name of the talk, and the fact that quite a few of these talks are very thinly veiled infomercials (much like every conference, I guess).

But what they talked about as far as the topics go were very interesting. The accessibility aspect was one of the ones that impacted me the most, in the sense of how we handle and should handle accessibility in Liferay.
Things like capturing keystrokes, and making sure to tab through the document were things that they addressed, and they listed off some facts that helped me personally realize just how large the market is for accessibility issues, as well as just how important it is for all.
To be honest, many developers have a hard time embracing the issue of accessibility. It seems to be an afterthought in most web applications, and much of the time it really is.
The problem, I think, stems from a lack of knowledge on just how many people have some sort of disability that hampers their access to the web, and just how possible it is for any one of us to be in a similar position.

I will confess that those two issues were responsible for my feelings on accessibility.
But what I didn't know was that:

  1. People with disabilities in the U.S. have over $175 Billion dollars in discretionary income every year
  2. Over 60 million people in China have a disability.

The other side of the talk was the internationalization issues in Javascript, which go way beyond our just submitting string keys. Things like date, time, currency and numeric formats are all issues that need to be taken into account. I have to give the Dojo team a lot of credit for what they've done in the i18n area, as well as the accessibility area.

Advanced Prototype by Stu Holloway
 Since I'm not a big Prototype user, and we're using jQuery so heavily, it may be a bit surprising that I visited this session, but I always love hearing new ideas, and the Prototype team has some really good ones.
 First, Stu is an awesome presenter. Something about him, his mannerism or something, remind me of Steve Carrell, so it was pretty entertaining.
 He was a big Javascript 2 basher, but he had a lot of interesting things he talked about with new functionality in Prototype, and you can tell he has a lot of experience in the industry.
 I can't say I agree with everything he said, but overall it was pretty interesting.
 I breifly stopped by the Comet presentation, but it was pretty dry, so I decided to step out and begin writing this blog post.
Stylesheet based Behavior by Dan Yoder
This talk was by far the most boring I've ever been to. I had to walk out, because not only was the talk only vaguely related to what the title is, Dan seriously was uncomfortable in front of everyone.
The whole thing was just this push his super esoteric javascript library that no one has heard of, has little to no community, and from a design standpoint doesn't really offer any benefit.

It was pretty darn painful.

After the sessions, I went back to my room for a while, where I was able to follow up on some emails, bug fix requests, etc, all of which I'm still trying to keep up on.

Later on that night, I went out to dinner with the jQuery team, and John Resig and I talked for a while about some different ideas, and some proposals for jQuery and some ways that Liferay can help them and they can help us.

It was really interesting to say the least, and when I am able to, I will talk about some of the different ideas we have for jQuery, and some interesting ways we might be working together in the future.

I'm looking forward to a lot of tomorrow's sessions. An old friend of mine lives in town, so we're going to be going to dinner.
Mike Young has been pestering me to visit Mike's Pastry, which seems to be every bit as well known as Mike has been saying, so I am going to be checking that out.

I will most likely be working a bit in the morning, so I will miss a few of the opening sessions, which is fine, seeing as they're all pretty introductory (Intro to jQuery, Introduction to contributing to an Open Source project, etc).

Until tomorrow, I am outta here :)

The Flash Rendering Engine

Company Blogs October 24, 2007 By Nate Cavanaugh

One of the most annoying things of late has been the slow "glacial" pace of the W3C, which is the standards body for HTML/CSS.

It's been bandied about by most professional web devs in the blogosphere that while Flash has gone through 9 versions of it's software in the past 10 years, HTML 4 has not changed, and CSS 3 has not even been finished, let alone implemented in any consistent or in depth way by any of the browser vendors (and who can blame them? It's hard enough implementing a strictly defined standard, let alone one that keeps changing every other year).

Flash, however, keeps growing, changing, adapting AND is more consitently adopted across all platforms and browsers than either Javascript or CSS. If you design something in Flash, you can pretty much guarantee that 99% of people will see what you want them to see, and interact with your application in a consistent way.

Now, I have quite a few issues with Flash. For one, it's IDE and workflow are really terrible. Sure, some people love it, but even hardcore Flash nuts will tell you it's IDE is horrible. It's not search engine indexable, it has some usability problems, and feels clunky much of the time.

However, during all of this discussion on the web about the standards body's slow, tired and frustrating pace, it struck me that there may be a happy medium where commercial innovation and open standards could not only live together and play nice, but complement each other in a powerful way.

What if Flash became the modern rendering engine of the different browsers? Flash can already access not only the DOM of your page, but also the Javascript you've inserted as well as the CSS you are styling with.
What if Flash could read your HTML and compile the resulting information into a swf at runtime?

Here is what I am imagining:

You're designing your HTML page. You have your DOCTYPE, your opening HTML tag, your head, your body, and your content.
Let's say you pass in a trigger via a comment at the very top of the page such as


so now, the currently installed Flash plugin looks for that comment at the very top of the HTML page, and replaces the contents of the body tag (this is all done on the DOM level) with a compiled version of the page that now runs in the Flash environment.
So now, let's say you're using CSS to style your page, you now know that this page looks the same in every browser, and behaves the same way.

Flash could also decide to read the head of the document, and allow people to link to actionscript files, like so:

<link href="/as/" rel="flash" type="text/actionscript" />

Which would allow you to use ActionScript to modify and control your page, adding another powerful behavior layer to your page, that has a wide range of serverside components as well as front end abilities.

There would be many benefits to this, for not only us lowly web developers, but also for Adobe AND the standards bodies.

The benefit for web devs would be a consistent and reliable platform that we can have as a base, and being supported by the innovation and development speed of a commercial organization. The benefit for the standards bodies is that it can take its time in adopting fully tested ideas, without angering the people it's claiming to help.

The benefit for Adobe, however, is the most important one to talk about. If they don't see a real commercial advantage, they will have no desire to pursue this. Their stakeholders as well as their head honchos must see a practical way in which this can help them.
And the benefit for Adobe is that they are more fully entrenching Flash to be the dominant platform, while being able to play off of existing standards and development techniques.

We would have the ability to develop a site in a way that is comfortable for us, but allowing us to tap into the power of Flash. Developers would begin to see Flash not as a new platform to learn, but as a complement to their work. This will mean that many developers who normally wouldn't see Flash as an option will begin to explore it's possibilities.
This will give Adobe a chance to shine on the server side as well. Increased usage and adoption means that they can customize enterprise Flash components, sell server side Flash interpreters, and many new avenues of revenue that spring up when a customer base is there.

But what does this mean for everyone? It means that you could design a really slick RIA that fails amazingly gracefully. If flash isn't supported, or they're using an old version, your site will still render pretty darn close.
This also means that when the different search engines crawl your site, they are still able to read the text, but it also allows the search engines to read the contextual HTML elements and give weight to each.
It means screen readers can read a page with no problem.
It means Adobe could pioneer new development techniques, and it means that they can help develop fixes for issues like CSS not having a true column solution, or allowing multiple backgrounds per image. And it would be able to progress the web incredibly fast.
It means that normal folks can tap into the power of Flash without having to understand timelines, layers, and the other complex intricacies of the current Flash paradigm.

Now, I am sure this is no small feat. But it benefits us all, and I for one am wondering when Adobe will step up and decide to do it.

4.3.3 - Some new, interesting changes

Company Blogs October 9, 2007 By Nate Cavanaugh

Pagination sweeping the nation.

Well, Liferay version 4.3.3 has come out with 2 new "features" (they're more improvements), but I was really happy with how they came out.

The first one is that we've fixed our horrendous paging mechanism. The old way of selecting pages was annoying to say the least. Let's revisit our old friend:

That beast is simple and all, and I love me some simplicity, but it's deceptively hard to use, and really uninformative.
The first input box is the one that holds the current page. Why is it an input box? So you can custom enter in your page number of course!
But sitting right next to this input is an arrow that leads almost everyone to believe that it takes you to the next page.
Whoops! Sorry, it submits whatever you've entered into the page. How insane is that?

But who in the world wants to do that? Why do I have to type anything at all? Sure, if you're a keyboard wizard, fine, but since our little paging bar only exists at the bottom of the results, we have to scroll down to the bottom of the page, then click into the input box, switch our focus from browsing to typing, or we can just hit next.

The other problem with this old bar is that it only sat at the bottom of the page. By default, the results per page in Liferay is 20. That's a pain to have to scroll to the bottom of every result set whenever you want to go next.

A use case is, let's say you have multiple pages of content, and you're looking for an item. You don't quite know what page it's on, but it's somewhere in the first 3-5 pages. You click next, scroll down, click next, scroll down, click next, scroll down.
What a pain.

Also, let's say you have less than 20 items, or if you've changed your default result-per-page set. Let's say you have 17 items. How would you ever know it from this page?
You have to manually count each item, which is another huge pain.

So enough griping, how did we improve it?

Here is what the pagination bar looks like in Liferay 4.3.3:

You'll notice that it now let's you know how many are on the current page, what page your on, and better looking links for navigation the pages.

You'll also notice that there is a select drop down box instead of an input. This allows both the average user, and our speed keyboarders who navigate everything with shortcut keys a way to select the page you wish to go to.

Also, the new pagination bar is a bit more intelligent. If you have less than 10 results, it will only show the bar on the top. Why is this? Because chances are, you can squeeze around 10 results and the search bar into a pretty tight space in your browser. Most people don't need to see two paging bars if the actual result set isn't long enough to warrant any scrolling.

Overall, there are a lot of little changes like this that can go a long way to helping everyone understand the interface, and browse through the website more quickly.

Theme properties are a changing

In versions prior to Liferay 4.3.3, to set up a theme, you needed at least 2 XML files. XML is nothing short of a pain in the rear to use.

I understand that it helps machines communicate better. That's fine. But the machines exist to serve us, not the other way around.
When we force our users to use XML files when other files will suffice, we're not helping people be productive.
We're being lazy.

The XML files also contained data that was repetitive. Why should someone have to change the name of their theme in 3 different places? This is rife with possible errors, files falling out of sync, etc.

So, with that thinking in mind, we've added the ability to use just 1 .properties file that will contain all of your theme's meta data.

The XML files can still be there, but the default, recommended way is to use just the one file.

The contents of the file look something like this:


tags=1-column, 2-column, 3-column, 1-2-1-column, 2-2-column
short-description=Texas Hold'em anyone?
change-log=Adapted to the latest version of Liferay.
author=Liferay, Inc.

I'm not saying that XML is horrendous. It's incredibly powerful, but when flexibility and "power" become an obstacle, is it really any more powerful, or is it just more dangerous?

So, with all of that, enjoy Liferay 4.3.3!

[IDEA] Highlight messages by sender in Mail interfaces

Company Blogs October 2, 2007 By Nate Cavanaugh

One thing I've wished was a reality for Mail applications is to highlight all messages by a certain sender. I know everyone sorts and groups their emails differently, but I would think that sorting messages by Date is one of the most common.
Sure, some people sort by title, some by Read or Unread status, but by far the most common use case I've seen is to sort by date, so you know you're seeing the most recently sent.

However, many times I'll need to find a message by that sender. For instance, if Brian Chan emails me about developing a new interface for something on Tuesday, and on Thursday, writes another email asking if I got the first email.

This new email is out of the scope of a "thread" of emails, so grouping my messages by thread doesn't really help. Also, while I can sort by Sender, it can be cumbersome to find the right block of emails, especially if there is a lot.
I would go so far as to say that sorting by Sender is more often a hassle than it is a help.

So the solution I've come up with is that when you select a message, all messages from that sender will be automatically highlighted. This way, I can select the one I am reading, then scroll down in my pane, and see the most recent emails Brian has sent me.

Here is an example of what I am talking about (click for a larger version of the image):
Email UI Idea

I am sure that this is actually pretty simple to do in a Thunderbird plugin, but it would be nice if all mail interfaces adopted this thinking.

Or perhaps it's an edge case. What do you think?

An intro

Company Blogs September 18, 2007 By Nate Cavanaugh

Hi there, if you're reading this, let me say hello and give you a warm thank you for stopping by.
My name is Nate Cavanaugh, and I am the Director of User Interface Engineering here at Liferay. What does that title even mean?
Well, it basically means that I have minions do all of my work for me, while I blog online ;)
Actually, it means that I'm the guy who is in charge of the UI, and (willingly) takes the lumps when it's bad (which it is), the themes in Liferay (architecturally speaking), the Javascript and AJAX, and pretty much the entire front end.

I have been with Liferay since November of 2006, and in that time, there are have been many changes to the front end, most prominent is the new themes architecture. I've also made a lot of changes to the Javascript, and helped polish some things up.

Of course, I didn't do any of that alone, and there were and are many different people who helped, including folks like Brian Chan, Jorge Ferrer and many others.

A little background on me: Before joining Liferay, I was briefly a Senior PHP Developer for Pricegrabber, a Front End Developer for Juxt Interactive, and the Art Director for PowWeb.
The product I am most "known" for was the now defunct Expanse CMS, which was a PHP based content management system designed for artists, designers and other creatives.

I also run my own website/blog/portfolio, Alterform.

My background is in graphic design and PHP development, and let's just say that I have some very strong opinions about both :)

One of the things I am most passionate about, however, is user interaction. There is an incomparable feeling of joy when you use a product for the first time, and things just make sense.
And there is an incomparable feeling of rage and hatred when things don't.

One of my favorite quotes (oft-quoted and for good reason) comes from Mr. Albert Einstein:
"Any intelligent fool can make things bigger, more complex, and more violent.  It takes a touch of genius - and a lot of courage - to move in the opposite direction."

For me, it's the little things that drive me crazy. I want to know why the things in this world can't just make sense.

For instance, the light switch in my apartment. When I first walk in, my goal is to turn on the light inside. One would assume that since that's most people's first priority, they would make the switch that controls the light inside the one closest to the door.
But no. For some reason, they decided that the switch closest to the door should control the outside light.

And I look at that, and I ask "why"? Why can't we have things that just make sense?

And that sort of anal retentivity, that sort of obsessed compulsion to make things easy is what I hope to bring to Liferay.

I want Liferay to be a product that you enjoy using. Not only that, but I've found that most of the people who advocate Liferay and opt for it, require other people to use it.
And it's to those people I feel the biggest kinship. To them, I hope to give the gift of usability.

Most of us will muddle through what we're using, including our company intranets, our bank's website, our content managment system.
We'll overcome the errors, and come to get used to the defects.

But there is a better way, and I would like to help bring it to reality.

We have some really great ideas, and a lot of great people working here, and I plan on using this blog to not only talk about those ideas and people, but to also explore ideas and concepts that perhaps we're not used to.

However, one of the things that annoy me about a lot of blogs (my own personal one included), is that it assumes that people really only want to sit under the vent of hot air that usually comes forth from a lot of blogs.

In that spirit, I plan on offering some resources, perhaps some tutorials, some tidbits that will hopefully make your life run more smoothly.

If you can, I recommend sticking around. I promise I'll do what I can to make it interesting.

Look forward to seeing you here :)

Showing 21 - 39 of 39 results.
Items 20
of 2