Just getting my feet wet in Open Laszlo
here's my shoutBox written in openLaszlo frontend and PHP backend.
Try closing the shoutBox, it is animated :)
type="application/x-shockwave-flash">
Click here if you do not see the flash embeded
So the idea of writing this simple application is just to get my feet wet in Open Laszlo. As we are moving to web 2.0, writing RIAs will be the future for web programmers. Many frameworks now have ajax plugin. I wrote my first ajax chat script in 2005 without any libraries. I'm sure it's much easier to write one with plugins. But it was still nice to write one from scratch. You then truly understand how it works. Competing with adobe's flex, google's GWT (ajax framework), possibly Microsoft's new silverlight there is an open source project called open laszlo. If you look at their demo applications, it seems to be pretty powerful. I think it's a very interesting alternative to ajax so I gave it a shot.
Motivations
Webcast tutorial
I learned about open laszlo from a coworker. I watched this webcase tutorial that came with their latest release open laszlo 4 and thought it was very cool.
I CAN USE PHP!
Originally I was not too thrilled to find that I must run the laszlo java servlet in order to compile the lzx files. Since all of my sites are hosted on LAMP servers, I would not be able to show off my end result if it only runs on java. Then I found this tutorial on how to use a php backend for open laszlo, it gave me a great head start.
Awesome community
Despite the fact you have to be approved individually to post on their forum, they have an awesome community. For the basic stuff I did, I found all my answers viewing the forum and looking at their great documentation.
How to create a form
Last weekend I started off by trying to understand some basics. First, how to create a form. Obviously just like good old HTML, you need some kind of protocol to communicate with the backend server. Open Laszlo supports HTTP post and get and many others. Originally looking at the php open laszlo tutorial, I was disappointed to find that you must manually create a post request.
First you create an “input field” if you will:
<!-- Editable text input field -->
<edittext id="nameEntry" width="160"></edittext>
Then on the “submit button”, you have to manually create a request:
<button width='160'> Join Guest List
<method event="onclick">
var dataEntry = canvas.datasets.EasyDataEntry;
var passedData = new LzParam();
passedData.addValue("guestName", nameEntry.getText(), true);
dataEntry.setQueryString(passedData);
dataEntry.doRequest();
</method>
</button>
This is a big turn off. I was like what is this? We are going backwards now? Even HTML does not make you REPEAT your input fields. Unsatisifed with the result, I spent a lot of time figuring out a better way of doing a form submission. I knew from their learn open laszlo in 10 mintues that there is a form element. It could be a newer element so the author of the tutorial didn’t use it. Once I figured it out, it is really quite simple.
First you create a dataset (btw, all data communication with Open Laszlo is done in XML)
<dataset name="echoer" src="shoutBox.php" request="true" type="http" querytype="POST" />
Then you create a form with a submit element that references the dataset. (btw, form is really a combination of a data form and a special view/layout)
<form x="0" y="0" width="100%" height="40" layout="axis: x; spacing: 6">
<submit name="submitter" data="${echoer}"/>
<edittext width="120" name="firstName" />
<button isdefault="true" onclick="parent.submitter.submit()">Submit</button>
</form>
This is pretty much equivalent to the HTML form:
<form action="shoutBox.php" method="post">
<input name="firstName" />
<input type="submit" value="Submit" />
</form>
Form validation
Despite being version 4.0, there is no official build-in form validation packaged with the release. THERE IS however a very nice library proposal. It’s also packaged in the download inside of the components/incubator folder. However for my purpose, I do not need all the functions in the library. All I wanted was to make sure both “name” and “message” fields are filled in before the form is submitted. Checking for the empty fields is not a big deal but trimming the field inputs is. Since Open Laszlo does NOT have regular expression support, a trim method must be written with split and join.
<method name="dotrim" args="s">
<![CDATA[
// the worst trim method ever?
var aEntry = s.split(' ');
var tEntry = new Array();
for (var n = 0; n < aEntry.length; n++) {
if (aEntry[n] != '') {
tEntry.push(aEntry[n]);
}
}
return tEntry.join(" ");
]]>
</method>
Although it may not be the worst trim method ever, it’s pretty yucky. Without regular expression, complex formatting and validation will be difficult.
Displaying data
Displaying data in Open Laszlo is pretty straight forward. You read the data from an XML and then use Xpath to point to the data you want to display. I used a few views for mine.
btw, boxview is a library I stole from the incubator.
<view name="congrats" width="100%" height="87%" clip="true">
<datapath xpath="echoer:/response" replication="lazy" />
<view layout="axis: y">
<boxview datapath="post" layout="axis:y" bordersize="0" paddingsize="6">
<view layout="axis:x">
<text datapath="@name" fontstyle="bold"/><text> said: </text>
</view>
<text resize="true" multiline="true" width="${this.parent.parent.parent.width-24}" datapath="text()"/>
</boxview>
</view>
<scrollbar axis="y" />
</view>
Eye candies
Being the UI person I am, I cannot finish my work without UI touches. First I added alternating rows for my data display. This is nothing like HTML. I found this piece of advice from the forum.
<!-- remember what color this row should be. -->
<attribute name="rowcolor" type="color" value="0xdddddd" />
<!-- set the alternating row color -->
<method event="ondata">
// close the adding window
adding.close();
shoutBox.setOpacity(1.0);
// set the alternating row color.
var pos = this.datapath.xpathQuery('position()');
if (pos % 2 == 0) {
this.setAttribute('rowcolor', 0xf3eee1);
} else {
this.setAttribute('rowcolor', 0xdcd0b1);
}
this.setBGColor(this.rowcolor);
</method>
<method event="onmouseover">
this.setColor(0xffffff);
this.setBGColor(0x4b564b);
</method>
<method event="onmouseout">
this.setColor(0x000000);
this.setBGColor(this.rowcolor);
</method>
Then I played with fonts. It’s really sweet that you can include your own ttf files to have complete control over font faces.
<font name="04B_21" src="04B_21.ttf" />
But I don’t like the fact it automatically apply anti-alias to any fonts. This makes using pixel fonts difficult. I tried many different pixel fonts, only 04B_21 looks good with the anti-alias applied because it doesn’t look like there is anti-alias. However, the lower case for 04B_21 are symbols so I cannot use it for all text for the window. So I was only able to use it for the button text. I wish there is a anti-alias attribute where you can select “none” like photoshop XP. boy, am I dreaming?
I also looked into styles for various things. I know CSS is supported. I cannot see how you can do modern development without the concept of CSS. However obviously since you can now control a lot more for the components, you have different syntax. Open Laszlo also has some build in styles. Here are some examples for a window. I used the greenstyle for my shoutBox window.
Animation
When I started writing this blog entry, I realized my shoutBox doesn’t have any animation. I was just saying to myself that one big advantage flash has over ajax is animation. It’s a lot easier to do animation in flash than ajax. And since Open Laszlo makes animation even easier, how can I not have animation in my project? I quickly added some animation on window close and faded the window after a shout is submitted. As expected, it took very little time and only a few lines of code.
<method name="close">
closeIt.doStart();
</method>
<animatorgroup name="closeIt" process="simultaneous" duration="1000" start="false">
<animator attribute="width" to="0" />
<animator attribute="height" to="0" />
<animator attribute="x" to="20" />
<animator attribute="y" to="20" />
<animator attribute="opacity" to="0" />
</animatorgroup>
After I added the animations, I was wondered how much bigger the flash file became. To my surprise, it was only 1kb bigger.
Coding in XML
Coming from java, php, javascript background, coding in XML takes a while to get used to. Fortunately in Open Laszlo, you can pretty much use javascript like syntax for most of your real code inside of CDATA
So it’s really not too painful.
My source code
Here’s my Open Laszlo my source code for my shoutBox. Feel free to steal from it if you need ![]()
Posted at 10:55PM Feb 13, 2008 by ying in Rich Internet application | Comments[0]
toString covers up nullpointer
While the project I'm working on is ready for production, I've gotten a few bug reports from the end users. One of them comes from a print page of an event schedule.
Here's the data model
Event has many Timeslots which has many Appointments, Timeslots & Appointments then become the schedule of an event.
Therefore to print the schedule of an event, I created a JSF page that prints it out via two dataLists.
<t:dataList value="#{eventAction.currentEntity.timeslots}" var="timeslot">
<t:dataList value="#{timeslot.appointments}" var="appointment">
...
</t:dataList>
</t:dataList>
The initial error the print page gives is outOfMemory exception (running out of Java heap space). I then tracked the error down to this particular line in the JSF:
<s:currencydisplaynolabel currency="#{appointment.screeningsTotal}" />
So I looked into the getScreeningsTotal method on my Appointment object. While debugging thru line by line, I noticed that when my cursor lands on this line, and opens up event (appointment's grandparent) in the variable screen, it causes countless queries to be run.
this.getParentEntity().getParentEntity().getQuantityDiscounts()
To debug, I added the line
Timeslot t = this.getParentEntity();
Event e = t.getParentEntity();
System.out.println(e);
Every time I hit the line System.out.println(e); so many queries are run and eventually the application runs out of memory.
I was convinced that something weird was going on with hibernate. It seems as if hibernate no longer does any lazy loading. It tries to pull all the child, grandchild etc objects under Event out while loading it. This should not have happened. All collections on the event should be lazily fetched.
After trying many different ways to solve the issue to no avail, I talked to Travis and he hinted that the toString method on event is probably doing something weird. System.out.println(e); after all calls the toString method. Then I looked into it...
Everything in the application extends baseEntity in the app. Thus the hierarchy is
BaseEntity -> Account -> Event -> Timeslot -> Appointment
and the BaseEntity toString() method contains:
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
So when it's printing the event obj, it loads all of its child collections which then load all their child collections so on and so forth.
After I put a break point in the toString method in the BaseEntity, I noticed that before the millions of queries were run, there was actually a nullpointer exception thrown. Since the eclipse console was too busy printing all hibernate queries, the original nullpointer exception was completely covered up. Tomcat log also only shows the outOfMemory error.
I still do not know what exactly is calling the toString method since it's called AFTER the nullpointer exception is thrown. It could be called by facelets when it is trying to print the stack trace on the screen.
Ultimately the lesson learned is that:
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
Although the line above looks very cool to stick in a toString method, DON'T DO IT in the base object when all your domain models extend that object.
Posted at 12:18PM Dec 04, 2007 by ying in Java | Comments[1]
Clear left workaround
You may have run into this problem, you may have not. But I found an acceptable workaround to this particular problem.
Here’s the scenario.
So I have a two column layout where my navigation list (red) is floated to the left and my main content is on the right. In my main content I have another navigation list (gray) that floats to the left. And the text in my main content now wraps around. I really want my main content text below the gray navigation to still to the right of red navigation.
If I use a simply use a clear:left on the container around my content text, I will have it all the way below the red navigation list. This is expected behavior as clear:left means make sure there is no elements that are floated to the left of me. It however is not the ideal behavior I wanted.

In IE & Firefox (possibly other browsers) there is a *bug* that if you wrap the floating element in a fieldset, the fieldset acts as a container that stretches as far as the float elements.

This however really isn’t a good workaround because it uses a *bug* in both browsers and it DOES NOT work in browsers like safari. So I came up with a better solution today.
Float the ul element to the right with its width set to 100%, and then clear the container around the text to the right. This obviously only works if you don’t have anything above the text that’s also floated to the right.
Posted at 12:02PM Oct 18, 2007 by ying in UI Design | Comments[0]
How to STYLE a table using CSS (JSF examples)
Tables are very important parts of the web interface. They are (hopefully) used for tabular data. It is one of the oldest and most basic HTML presentation tag but in order for it to smoothly fit into the new CSS age, we need to look at the most practical way in correctly setting up the markup and the CSS.
Nowadays, we no longer wish to make separate instances of a similar application for different clients. We want to thrive on making a single application that will fit the needs of as many clients as possible. This task is very challenging. In my opinion the ideal situation is to have the clients and developers both understand the benefits of the end goal and compromise to reach it. As developers we can always dream to have a single application reach the level of customization we can accomplish with many separate applications and yet don’t confuse the heck out of the end users. While I am unsure if that’s ever a possibility, I know ways that might help get us closer.
One of the biggest challenges is to give each client who uses the same application their own unique UI presentation. This is no small task and I only plan to address a small issue you might encounter in accomplishing this task. That’s how to mark up a table with the most amount of UI flexibility.
A traditional table might look something like this:
<table>
<tr>
<th>
Name
</th>
<th>
Phone number
</th>
<th>
Date of birth
</th>
</tr>
<tr>
<td>
Mike White
</td>
<td>
123-456-789
</td>
<td>
10/11/1976
</td>
</tr>
<tr>
<td>
Nancy Green
</td>
<td>
987-644-311
</td>
<td>
02/24/1950
</td>
</tr>
</table>
With no CSS classes specified in any elements, it will be hard to style this table with much customization. You can add styling to the table, tr, th and td tags but they will have to be uniformly defined. You will have a lot more flexibility if add more classes to each element like below:
<table class="people" cellpadding="0" cellspacing="0" border="0">
<tr>
<th class="first">
Name
</th>
<th>
Phone number
</th>
<th class="last">
Date of birth
</th>
</tr>
<tr class="odd">
<td class="name">
Mike White
</td>
<td class="phoneNumber">
123-456-789
</td>
<td class="dateOfBirth">
10/11/1976
</td>
</tr>
<tr class="even">
<td class="name">
Nancy Green
</td>
<td class="phoneNumber">
987-644-311
</td>
<td class="dateOfBirth">
02/24/1950
</td>
</tr>
</table>
Notice I applied classes to the table, each of the alternating rows and each of the columns. And also notice I added
cellpadding="0" cellspacing="0" border="0"
to the table tag. This is very important since CSS does not have direct cellpadding and cellspacing controls, you cannot take away the natural cellpadding & cellspacing each browser applies to all tables. It’s the best to set them to 0 and control everything via CSS.
Since I’ve been working with JSF, I will give an example in JSF. The t:dataTable tag can very easily generate the table markup above.
Now we have the markup, let’s go thru a simple table styling.
The first things I’d start with are these:
table.people {
width: 100%;
border-collapse: collapse; /* so we can control cellspacing in a practical way */
}
table.people th,
table.people td {
padding: 5px;
text-align: left;
font-family: Arial, Verdana, sans-serif;
}
Let’s see how it looks:

I usually apply border-collapse: collapse on the table so you can control the border width with td tags and without seeing double borders between cells. The padding on td & th tags really work just like cellpadding inside of the table tag. Except you have more flexibility now as if you really want, you can have different paddings for every cell.
Now let’s add some border.
Change the previous th,td styling definition to below:
table.people th,
table.people td {
padding: 5px;
text-align: left;
font-family: Arial, Verdana, sans-serif;
border: 1px solid #000; /* let's apply borders */
}
Let’s see how it looks:

Now this is the look you usu. want. If you take away the border-collapse: collapse; and then your table will look like this:

TIP: do not apply border on the tr tag since it does not understand it. To get borders on tables, always add border defintion on td and th tags.
Now let’s give the table header a different background color, add the alternating colors and border colors.
table.people {
width: 100%;
border-collapse: collapse; /* so we can control cellspacing in a practical way */
border-bottom: 1px solid #000;
}
table.people th,
table.people td {
padding: 5px;
text-align: left;
font-family: Arial, Verdana, sans-serif;
border: 1px solid #000; /* let's apply borders */
border-bottom:0;
}
table.people th {
background-color: #ddd;
color: #BB0000;
border-bottom: 2px solid #000;
}
table.people tr.odd {
background-color: #DDFFFF;
}
table.people tr.odd td {
border-top: 1px solid #ccc;
}
table.people tr.even {
background-color: #FBFBFB;
}
table.people tr.even td {
border-top: 1px solid #BBEEEE;
}
Let’s see how it looks:

TIP: table bottom border does not override td bottom border (I’m not sure if it’s a bug) therefore it’s important to NOT define a td bottom border and define a table bottom border if you want them in DIFFERENT colors and/or styles.
Let’s talk about cellspacing. Personally I’ve never found a real need for cellspacing in styling tables. It is something CSS cannot truly accomplish with limited support of border-spacing in browsers (mainly it’s not supported by IE 6). However, you may be able to *fake the look* by using a border color that’s the same as the solid background color. Please take a look at the example below.
body {
background-color: #000;
}
table.people {
width: 100%;
border-collapse: collapse; /* so we can control cellspacing in a practical way */
border-bottom:0; /* you may not want the bottom of your table have spacing */
}
table.people th,
table.people td {
padding: 5px;
text-align: left;
font-family: Arial, Verdana, sans-serif;
border: 4px solid #000; /* this can be seen as cellspacing... */
border-bottom:0;
}
/* you may not want the top of your table have spacing */
table.people th {
border-top: 0;
}
/* you may not want the left most and right most side of your table have spacing */
table.people th.first,
table.people td.name {
border-left: 0;
}
table.people th.last,
table.people td.dateOfBirth {
border-right: 0;
}
table.people th {
background-color: #ddd;
color: #BB0000;
}
table.people tr.odd {
background-color: #DDFFFF;
}
table.people tr.even {
background-color: #FBFBFB;
}
Posted at 11:58AM Oct 18, 2007 by ying in UI Design | Comments[2]
Eclipse Tips
In order to clean up the project view in Eclipse, you can hide the files you don't need. First of all, make sure you're in the Java Perspective (Window ? Open Perspective). Then click the little (down) arrow in the top right corner of the Package Explorer pane. Select Filters, check the "Name Filter Patterns" and type "*.jar" (no quotes) in the text field. Then in the list of elements, scroll down and check Referenced Libraries. Click OK to continue.
Another useful Eclipse trick is to use abbreviated package names. You probably won't need it on this project, but its nice on projects where you're inflicted with super.long.package.name.syndrome. Go to Window ? Preferences ? Java ? Appearance. Check the "Compress all package names" checkbox and type "1." (no quotes) in the text field.
The visual designer default to many file types is a pain. It slows down eclipse and is completely unnecessary. To stop Eclipse from loading your files into split panes etc, try following.
Window ? Preferences ? General ? Editors ? File Associations
Some of the ones I changed for mine are:
*.xhtml (Default to HTML editor)
*.jsp (Default to JSP Editor)
*.xml (Default to XML Editor)
*.sql (Default to SQL Editor)
Also you can turn off some of default eclipse plugins to further speed up your eclipse. You can turn them off at
Windows -> Preferences -> General -> Capabilities (expand the big plugin categories)
You can also export/import code style formats under
Windows -> Preferences -> Java -> Code Style -> Formatter
Posted at 10:24PM Oct 03, 2007 by ying in General | Comments[1]
Cutest Firefox Poster Ever!
Travis just sent me this cutest Firefox poster!! Everyone should get one.

I was very enraged by the JSF tag
h:selectOneRadio
Because it renders the radio buttons with the TABLE tag @_@ instead of something CSS friendly like list or div tags.
Fortunately if you use the tomahawk’s version of
t:selectOneRadio
You can render the radio buttons your own way.
Orientation of the options list. Valid values are “pageDirection” for a vertical layout, “lineDirection” for horizontal, or “spread” for developer placement. The default value is “lineDirection”. If the “spread” option is selected, this tag does not render HTML. Instead, the developer uses “radio” tags to position radio buttons for each of the SelectItem instances. See the “radio” tag for further information.
Here's an example of the code to use layout="spread"
<t:selectOneRadio layout="spread" id="diversityGroup" value="#{vendorSurveyForm.vendorSurvey.diversityGroup}"
tabindex="#{tabCounter.firstTabIndex}" enabledOnUserRole="#{vendorSurveyForm.canEditSurveyRoles}">
</t:selectOneRadio>
<t:panelGrid rendered="#{!vendorSurveyForm.cannotEditSurvey}" columns="3" styleClass="diversityGroup radioCheckboxesContainer"
columnClasses="diversityGroup1, diversityGroup2, diversityGroup3">
<t:radio index="0" for="diversityGroup" />
<t:radio index="1" for="diversityGroup" />
<t:radio index="2" for="diversityGroup" />
<t:radio index="3" for="diversityGroup" />
<t:radio index="4" for="diversityGroup" />
<t:radio index="5" for="diversityGroup" />
<t:radio index="6" for="diversityGroup" />
</t:panelGrid>
Posted at 09:25AM Sep 20, 2007 by ying in General | Comments[0]
Emulate Float Center
This entry talks about how to solve a common design scenario with different approaches. If you are not interested in the long explanation, you can just take a look the end result of my emulation.
Here’s the scenario. You have some menu items you wish to show to a user. Each item has an image and a text description. These items are shown based on the user’s role. Therefore one user may see two items while another may see ten of them.
Here’s a traditional way to handle it with table. Create a table and a table row and let the number of cells be dynamic. Add a cell if you need one.
<table width="80%" align="center">
<tr>
<td align="center">
<img src="images/viewUsers.gif"><br /><a href="#">View Users</a>
</td>
<td align="center">
<img src="images/searchSurveys.gif"><br /><a href="#">Search Surveys</a>
</td>
<td align="center">
<img src="images/editSurvey.gif"><br /><a href="#">Edit Survey</a>
</td>
</tr>
</table>
Here’s the outcome of this approach.
There is a couple issues with this approach.
Because you are trying to fit all items into one line, the more items you could see, the narrower the space becomes for each item. On the resolution 1024×768 (the most common one now) you will see something like:

The items are squeezed and may be hard to read. More importantly if you keep adding more items, the table will run out of space and will have to increase its width and intrude into nearby UI elements.
The code:
<img src="images/editSurvey.gif"><br /><a href="#">Edit Survey</a>
used to link the menu item also poses other issues. First you are not linking the image thus if you user clicks on the image, nothing happens. The user will have to very accurately click on the text in order to get a response. You could do this:
<a href="#"><img src="images/editSurvey.gif"><br />Edit Survey</a>
But that’s not much better. This will force you to style how the image tag should look wrapped in anchors and show unnecessary white space to be linked.
There is another problem with displaying the image inline. You cannot replace it with CSS. If you style the anchor in such a way that it uses the image as a background image, then that image can be easily replaced by changing the definition of the CSS instead of the markup.
The second way to handle this is using float:left and CSS block elements. This is nothing new and is widely acceptable.
Here’s the markup (it’s much cleaner than the table approach)
<ul class="mainMenu">
<li class="viewUsers">
<a href="#">View Users</a>
</li>
<li class="searchSurveys">
<a href="#">Search Surveys</a>
</li>
<li class="editSurvey">
<a href="#">Edit Survey</a>
</li>
</ul>
Here’s the css
ul.mainMenu {
margin: 0 auto;
width: 80%;
}
ul.mainMenu li {
float: left;
}
ul.mainMenu li a:active,
ul.mainMenu li a:link,
ul.mainMenu li a:visited {
display: block;
float: left;
color: #000;
text-decoration: none;
padding: 40px 10px 10px 10px;
text-align: center;
white-space: nowrap;
}
ul.mainMenu li a:hover {
text-decoration: underline;
}
ul.mainMenu li.viewUsers a {
background: transparent url(images/viewUsers.gif) center top no-repeat;
}
ul.mainMenu li.searchSurveys a {
background: transparent url(images/searchSurveys.gif) center top no-repeat;
}
ul.mainMenu li.vendorLists a {
background: transparent url(images/vendorLists.gif) center top no-repeat;
}
ul.mainMenu li.editSurvey a {
background: transparent url(images/editSurvey.gif) center top no-repeat;
}
ul.mainMenu li.report a {
background: transparent url(images/report.gif) center top no-repeat;
}
ul.mainMenu li.editProfile a {
background: transparent url(images/editProfile.gif) center top no-repeat;
}
ul.mainMenu li.vendorNotes a {
background: transparent url(images/vendorNotes.gif) center top no-repeat;
}
ul.mainMenu li.upgrade a {
background: transparent url(images/upgrade.gif) center top no-repeat;
}
ul.mainMenu li.lowYield a {
background: transparent url(images/lowYield.gif) center top no-repeat;
}
ul.mainMenu li.config a {
background: transparent url(images/config.gif) center top no-repeat;
}
ul.mainMenu li.faq a {
background: transparent url(images/mainMenuFaq.gif) center top no-repeat;
}
ul.mainMenu li.returnToHome a {
background: transparent url(images/home.gif) center top no-repeat;
}
ul.mainMenu li.logout a {
background: transparent url(images/logout.gif) center top no-repeat;
}

This approach basically solves all the issues posed by the table. It makes sure the menu item text is not forced into two lines. The menu item images are defined in the CSS instead of the markup. Also if you hover over the links, you can get a response in the close vicinity of the menu item instead of having to accurately click on the text or the image. Most of the people are probably pretty happy with it. I was too until I realized it CANNOT establish something that the original table approach had. That is to center all the menu items. Because we use float:left, I’ve researched many places to find a way to center the items but have come up empty handed. Only if there is a float:center than we would have no problem. Since there isn’t one, I’ve decided to emulate one.
The way I emulate is by completely dropping the float:left CSS definition and use inline instead of block elements for the menu item. This requires both CSS and markup changes. This is by no means the best way to do it but it’s the only way I know that will accomplish all what I look for. I still do not know the browser compatibility of this approach (only tested in IE 6 and FF 2 at this point). If you are not an advanced CSS designer, please stick with the float:left approach.
The inspiration for this approach comes from a fix for a IE bug. Inline elements DO NOT understand width, height or margin. So in order to accomplish the block element look, I have to rely on padding and line-height. Line-height is used to emulate margin.
The markup will become something like this:
<div class="mainMenuWrapper">
<a href="#"><span class="viewUsers">View Users</span></a>
<a href="#"><span class="searchSurveys">Search Vendors</span></a>
<a href="#"><span class="vendorLists">Vendor lists</span></a>
<a href="#"><span class="editProfile">Edit My Account</span></a>
<a href="#"><span class="vendorNotes">View All Notes</span></a>
<a href="#"><span class="lowYield">Low Return Search Results</span></a>
<a href="#"><span class="config">Configuration</span></a>
<a href="#"><span class="faq">FAQ</a></span></a>
</div>
The CSS has the infamous * html IE hack to make the output look the same in IE and Firefox. I will not go into the detail explaining it. Hopefully if you are looking to do this you understand enough about CSS to figure it out on your own.
div.mainMenuWrapper {
text-align: center;
padding: 17px 0 0 0;
margin: 0;
line-height: 80px;
}
* html div.mainMenuWrapper {
padding: 10px 0 0 0;
}
div.mainMenuWrapper span {
padding: 40px 15px 0 15px;
white-space: nowrap;
}
* html div.mainMenuWrapper span {
padding: 10px 15px 0 15px;
}
div.mainMenuWrapper a,
div.mainMenuWrapper a:link,
div.mainMenuWrapper a:active,
div.mainMenuWrapper a:visited {
cursor: pointer;
text-decoration: none;
color: #000;
font-weight: bold;
}
html div.mainMenuWrapper a:hover {
text-decoration: underline;
}
div.mainMenuWrapper span {
display: inline-block;
}
div.mainMenuWrapper span.viewUsers {
background: transparent url(../images/viewUsers.gif) center top no-repeat;
}
div.mainMenuWrapper span.searchSurveys {
background: transparent url(../images/searchSurveys.gif) center top no-repeat;
}
div.mainMenuWrapper span.vendorLists {
background: transparent url(../images/vendorLists.gif) center top no-repeat;
}
div.mainMenuWrapper span.editSurvey {
background: transparent url(../images/editSurvey.gif) center top no-repeat;
}
div.mainMenuWrapper span.report {
background: transparent url(../images/report.gif) center top no-repeat;
}
div.mainMenuWrapper span.editProfile {
background: transparent url(../images/editProfile.gif) center top no-repeat;
}
div.mainMenuWrapper span.vendorNotes {
background: transparent url(../images/vendorNotes.gif) center top no-repeat;
}
div.mainMenuWrapper span.upgrade {
background: transparent url(../images/upgrade.gif) center top no-repeat;
}
div.mainMenuWrapper span.lowYield {
background: transparent url(../images/lowYield.gif) center top no-repeat;
}
div.mainMenuWrapper span.config {
background: transparent url(../images/config.gif) center top no-repeat;
}
div.mainMenuWrapper span.faq {
background: transparent url(../images/mainMenuFaq.gif) center top no-repeat;
}
div.mainMenuWrapper span.returnToHome {
background: transparent url(../images/home.gif) center top no-repeat;
}
div.mainMenuWrapper span.logout {
background: transparent url(../images/logout.gif) center top no-repeat;
}
Here’s outcome along with some additional styling and context.
Posted at 10:12AM Aug 24, 2007 by ying in General | Comments[0]
