Introducing Graphic Menu in TYPO3

Exclusive offer: get 50% off this eBook here
TYPO3 Templates

TYPO3 Templates — Save 50%

Create and modify templates with TypoScript and TemplaVoila

$26.99    $13.50
by Jeremy Greenawalt | November 2010 | Open Source

A simple graphical menu object referred to as GMENU in TYPO3. GMENU is our next step above TMENU in power and complexity, but it's still a pretty easy transition if we take a few minutes to understand the concepts.

In the previous article, Introducing Hierarchical Menu in TYPO3, we have learnt various aspects of HMENUS in detail.

In this article, by Jeremy Greenawalt, author of TYPO3 Templates, we will:

  • Create your first graphical menu with a custom font, drop-shadows, and rollover actions
  • Create a breadcrumb navigation menu that helps users see where they are in the website

 

TYPO3 Templates

TYPO3 Templates

Create and modify templates with TypoScript and TemplaVoila

  • Build dynamic and powerful TYPO3 templates using TypoScript, TemplaVoila, and other core technologies.
  • Customize dynamic menus, logos, and headers using tricks you won’t find in the official documentation.
  • Build content elements and template extensions to overhaul and improve TYPO3’s default back-end editing experience.
  • Follow along with the step-by-step instructions to build a site from scratch using all the lessons in the book in a practical example.
        Read more about this book      

(For more resources on this subject, see here.)

Introduction

Our graphical menu, GMENU, has the ability to use a TYPO3 class, GIFBUILDER, to create images on the fly. We are going to look at GIFBUILDER in depth in just a moment, but the basic idea is that GIFBUILDER can help us build complex graphics for our menus dynamically so that we can use fonts that are not be supported by all browsers, build button-like graphics, and use drop-shadows and embossing for effect. This means that we don't need to update Photoshop every time that we want to change the menu titles or replace the font, and we also don't have to learn or use Flash or JavaScript just to create flexible menu titles.

We gain a lot of freedom and power with GMENU, but it does have some disadvantages compared to TMENU. Depending on our needs, we will be generating an image for every state (normal, rollover, active, and so on), for each menu item anytime we make a change. The nice thing is that TYPO3 will cache our images, so they are only generated after we make a change and reset the cache. Overall, we will use the server a little more heavily anytime we reset the cache, and our users will need to download images for each menu item. The last disadvantage is just that it is more complex than TMENU. If our frontend developers or designers have already provided us with some awesome CSS/JavaScript or Photoshop images, then we may only need a text-based menu. In return for those possible disadvantages, we will get freedom and cross-browser compatibility, so let's see what we can do before we make any decisions.

Introducing GIFBUILDER

GIFBUILDER is a universal object in TypoScript that uses some basic TypoScript code to generate images using the ImageMagick (or GraphicsMagick) library in PHP. Generating images with ImageMagick is normally very complex, and we would have to learn a fair amount of PHP to make anything. Using GIFBUILDER, makes it relatively easy to make these same dynamic images without learning PHP or opening Photoshop. GIFBUILDER can actually be used for any images that we would want to create in TypoScript, but we are going to be using it specifically for GMENU in this article to turn our text fields into typographic images complete with layers and effects.

We are going to learn about three main objects in GIFBUILDER that will help us create our menu items:

  • Boxes: We can layer simple boxes to make borders or button effects.
  • Images: We can use uploaded or external image files as backgrounds or just display them as menu items.
  • Text: Most importantly, we can use text objects to show our page titles in non-web fonts with drop-shadow or emboss effects.

A complete list of the properties available to GIFBUILDER is beyond the scope of this article, and not really necessary to build most menus. If you have any problems with GIFBUILDER, you may need to check your ImageMagic configuration in the TYPO3 Install Tool.

The BOX object

The BOX object is one of the key TypoScript objects in GIFBUILDER. The BOX object is, like it sounds, just a simple graphical box defined by its size and color. By itself, it's not that helpful, but we can add boxes as layers to generate borders and backgrounds that will be flattened into our final generated images. We are only going to use two properties for our boxes:

  • BOX.dimensions defines the dimensions of the box in the format x, y, w, h where x, y is the offset for the top right-corner and w, h is the width and height of the box.
  • BOX.color defines the color of the inside of the box.

Here is an example of a gray box, 400 pixels wide, 20 pixels tall, and offset 3 pixels down and to the right:

lib.subMenu.1.NO {
5 = BOX
5.color = #aaaaaa
5.dimensions = 3,3,400,20
}

The IMAGE object

The next object we can use, IMAGE, will bring in an image for normal display or basic tiling and masking. The IMAGE object can be used for complex displays, but we are only looking at menu applications and will just look at a few options:

Introducing Graphic Menu in TYPO3

The TEXT object

Finally, we're going to look at the options for a TEXT object in GIFBUILDER. TEXT objects are used to display any text we want in GIFBUILDER, but will be mainly using them to show the title of each page as a menu item. This list of properties is much more exhaustive because this would obviously be one of the most important objects to customize when we're creating a menu using graphical text:

Introducing Graphic Menu in TYPO3

GIFBUILDER layers

We work with GIFBUILDER by creating new objects for the GIFBUILDER, designing them with properties, and layering them by number values. Each layer is stacked in ascending order (larger numbers on top), and then TYPO3 generates a final image by flattening all of the layers into one image. It sounds a little complex, but look at this example:

lib.subMenu.1.NO {
5 = BOX
5.color = #aaaaaa
5.dimensions = 3,3,400,20
10 = TEXT
10.text.field = title
10.fontSize = 12
}

In the example that we just saw, lib.subMenu.1.NO is our GIFBUILDER object. Although the numbers used to identify objects (5 and 10 in the example) are sometimes arbitrary in TYPO3, they are very important for GIFBUILDER because they define the ordering in layers. GIFBUILDER stacks it's subobjects from lowest number to highest. So, in the example that we just saw, TYPO3 is generating an image in a logical sequence:

  1. A gray box is defined.
  2. The dimensions of the gray box are defined to make it 400 pixels wide and 20 pixels.
  3. A text object is created on top of the gray box to show the title field of the page from the menu item.
  4. The size of the text for the title is set to 12 pixels.
  5. TYPO3 generates a flattened image of our menu item title in a gray box.

Using this system, we can stack very simple objects on top of each other to draw basic buttons.

GIFBUILDER properties

The GIFBUILDER object will apply itself to all items in a GMENU menu. For the basic GIFBUILDER object, we are only going to look at two properties:

  • XY defines the size of the image (width and height)
  • backColor defines the background color for the entire image

The interesting trick for XY (and some of the other dimension properties) is that it can be based on hard-coded numbers and TypoScript constants, or it can be a calculation based on the size of another item. In the following code, the size of the GIFBUILDER object is tied directly to the size of the TEXT object declared below it:

10 = TEXT
10.text.field = title
XY = [10.w]+10,[10.h]+10

The references [10.w] and [10.h] read the current width and height of the object associated with 10. Then, we add 10 pixels onto each one to give ourselves a little bit of room for spacing. We'll use this technique in GMENU to make sure that our boxes and graphic objects always line up with our titles.

GMENU properties

The first thing that you'll probably notice going from TMENU to GMENU is that we are about to multiply the number of properties at our disposal dramatically. We've already covered the common menu properties. We're just going to cover the most basic or necessary properties in the following tables to get an idea of what we can do. If it looks intimidating, don't worry. Most of the properties are created logically and build upon our earlier knowledge. Most importantly, there's no requirement to learn all of GIFBUILDER before we start playing around.

The menu object itself has just a few key properties that we need to look at:

Creating our first graphic menu

The first change we can accomplish is updating our main menu with a custom font and some rollover functionality. We can do that with minimum fuss, and it'll update our whole look nicely. I chose a freeware font from Larabie Fonts (http://www.larabiefonts.com) called Deftone because it'll show off GIFBUILDER, and my boss loves it. You can use any TrueType font file you would like, though. Some fonts seem to work better with ImageMagick then others, so you may need to experiment. In any case, let's start updating our menu:

  1. We need to change lib.mainMenu.1 = TMENU to lib.mainMenu.1 = GMENU to use the GMENU objects.
  2. We want a consistent height for our entire menu, so we'll enable useLargestItemY in our template:

    lib.mainMenu.1.useLargestItemY = 1

  3. Let's update the normal menu state first. We won't be using the div tags around our menu items, so want to add a class to our images:

    lib.mainMenu.1.NO.ATagParams = class="menu-link"

  4. We can set the background color and dimensions of our menu items. We are going to use 10 for our text object, so we can go ahead and use that as part of the size calculation to make our items exactly the same width and 5 pixels taller than the text:

    lib.mainMenu.1.NO {
    backColor = #ffffff
    XY = [10.w],[10.h]+5
    }

  5. Now we can create the TEXT object. This is our main menu, so we're just going to use the title as our text content. We're also going to use the Deftone font at a size of 36 in a classic black:

    lib.mainMenu.1.NO {
    10 = TEXT
    10.text.field = title
    10.fontFile = fileadmin/templates/deftone.ttf
    10.fontSize = 36
    10.fontColor = #000000
    10.align = left
    }

  6. The main menu is already looking better, but we can add some flair by tilting the text up with the angle property. Because of the angle changing the dimensions, we'll push the text down a little more by adding a 50 pixel offset to the height:

    lib.mainMenu.1.NO {
    10.offset = 0,50
    10.angle = 3
    }

After all of our modifications, this is what our menu should look like:

TYPO3 Templates Create and modify templates with TypoScript and TemplaVoila
Published: November 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on this subject, see here.)

Modifying based on menu states

We can't deny that the menu is looking better, but we lost that rollover functionality that we were showing off in the TMENU. Luckily, we can add that back with just a couple lines of code. We can use the < operator to copy all of the NO properties over, then we can change the text to red and add a shadow whenever the mouse rolls over it with the RO state:

lib.mainMenu.1 {
RO < .NO
RO {
10.fontColor = #990000
10.shadow.offset = 1,1
}
RO = 1
}

If we want to differentiate the pages in the current rootline by graying them out, it's almost the same process:

lib.mainMenu.1 {
ACT < .NO
ACT {
10.fontColor = #999999
10.shadow.offset = 1,1
}
ACT = 1
}

In the following screenshot, you can see the results if we are on the Products page (so it's active) and roll over the Content Elements menu item with our mouse. We could almost show this off right now.

Main menu code

After all of the tweaking, our code might be getting ugly. If we take away the redundancies and use curly braces, this is what our code can look like:

## Main Menu [Begin]
lib.mainMenu = HMENU
lib.mainMenu.entryLevel = 0
lib.mainMenu.wrap = <ul id="menu-area">|</ul>
lib.mainMenu.1 = GMENU
lib.mainMenu.1.useLargestItemY = 1
lib.mainMenu.1 {
NO {
allWrap = <li class="menu-item">|</li>
ATagParams = class="menu-link"
backColor = #ffffff
XY = [10.w],[10.h]+5
10 = TEXT
10 {
text.field = title
fontFile = fileadmin/templates/deftone.ttf
fontSize = 36
fontColor = #000000
align = left
offset = 0,50
angle = 3
}
}
RO < .NO
RO = 1
RO {
10.fontColor = #990000
10.shadow.offset = 1,1
}
ACT < .NO
ACT = 1
ACT {
10.fontColor = #999999
10.shadow.offset = 1,1
}
}
## Main Menu [End]

Creating a graphic menu with boxes

Now that we've created a basic GMENU, we can get a little fancier with the submenu. This time, let's actually create buttons with embossed text. Because the emboss effect works better with certain fonts, we don't want to use the Deftone font again. I tried plenty of combinations early on, but I love the look of an emboss on a simple, serif typeface. I've downloaded an open source font from The League of Movable Type (http://www.theleagueofmovabletype.com) called Goudy Bookletter 1911, but you can use any font with clean, straight lines to get the same effect.

  1. We added a hefty margin to the submenu in CSS, but we don't really want to stop and modify our stylesheets while we're playing around. Instead, we can wrap our submenu in a ul with a reset margin to offset the styling. This wouldn't be a permanent solution, but it's handy while we're experimenting:

    lib.subMenu.wrap = <id="submenu-area" style="margin-left:
    0px">|</ul>

  2. Just like the main menu, we need to enable GMENU by changing lib.

    subMenu.1 = TMENU to lib.subMenu.1 = GMENU.

  3. This time, we won't worry about the height of the menu (it'll be consistent, anyway), but we do want all of the buttons to be the same width. We can set the menu to use the widest item as a base:

    lib.subMenu.1.useLargestItemX = 1

  4. Like the main menu, we need to add a class to the images for future reference:

    lib.subMenu.1.NO.ATagParams = class="submenu-link"

  5. This time, we'll define the background as a light gray. We are going to use 10 for TEXT object, so we'll set the width of each menu item to be 10 pixels wider than the text by using [10.w] + 10 for our width. We will set the height of the menu as a whole to 26 pixels so we have space for boxes and text inside. The background that is visible between the boxes will be a visual border around the entire area:


    lib.subMenu.1.NO {
    backColor = #bbbbbb
    XY = [10.w]+12,26
    }

  6. We're going to define a darker gray box for each menu item as our button:

    lib.subMenu.1.NO {
    5 = BOX
    5.color = #aaaaaa
    5.dimensions = 3,3,400,20
    }

  7. Next, we'll add a text field on top of the box. Remember, the numbering of our objects defines their layer, so we're going to use 10 to place the TEXT object on top of the BOX object:

    lib.subMenu.1.NO {
    10 = TEXT
    10.text.field = title
    10.fontFile = fileadmin/templates/goudy_bookletter_1911-
    webfont.ttf
    10.fontSize = 12
    10.fontColor = #555555
    }

  8. This time, we're going to set the offset and alignment to center the text horizontally and vertically in the boxes:

    lib.subMenu.1.NO {
    10.offset = 0,19
    10.align = center
    }

  9. Finally, we'll add the emboss effect using shades of gray to make the text appear sunken into the boxes:

    lib.subMenu.1.NO {
    10.emboss.offset = 1,1
    10.emboss.highColor = #cccccc
    10.emboss.lowColor = #bbbbbb
    }

Now that we've updated our submenu, it should look like this:

Submenu code

Once again, step-by-step modification doesn't lend itself to clean code. If we optimize our code and remove all the redundant lines, this should be our final submenu code:

## Submenu [Begin]
lib.subMenu = HMENU
lib.subMenu.entryLevel = 1
lib.subMenu.wrap = <ul id="submenu-area" style="margin-left: 0px">|</
ul>
lib.subMenu.1 = GMENU
lib.subMenu.1.maxItems = 8
lib.subMenu.1.useLargestItemX = 1
lib.subMenu.1.NO {
allWrap = <li class="submenu-item" style="margin-right: 0px">|</li>
ATagParams = class="submenu-link"
backColor = #bbbbbb
XY = [10.w]+12,26
5 = BOX
5 {
color = #aaaaaa
dimensions = 3,3,400,20
}
10 = TEXT
10 {
text.field = title
fontFile = fileadmin/templates/goudy_bookletter_1911-webfont.ttf
fontSize = 12
fontColor = #555555
offset = 0,19
align = center
emboss.offset = 1,1
emboss.highColor = #cccccc
emboss.lowColor = #bbbbbb
}
}
## Submenu [End]

Using external images for menus

Now that we've seen how we can generate images, we should look at using external images as well. It's going to happen quite often in the real world that a designer is going to already have icons or images designed for our menu that can't possibly be replicated dynamically with GIFBUILDER. In our case, we'll imagine that our boss wants to use some special graphics for each main menu item. We want the editors to be able to update these images in the future without breaking our template or bother us, and it's probably a good idea to make sure that we fall back to a GIFBUILDER image if somebody forgets to assign an image to a menu item in the page properties.

The first thing we can do is adding an alternate image property to our menu items with the altImgResource property. The altImgResource property takes some of the same file parameters as the beforeImg functions we saw earlier:

altImgResource.import = uploads/media/
altImgResource.import.field = media
altImgResource.import.listNum = 0

Using these parameters, our menu can import images associated with our pages through the resources tab in page setup. By assigning the listNum to 0, we will pull the first image from the list. We can also assign higher numbers in the list to use different images for rollover and active states as well. It's easier to understand if we see this in action, so we can add the altImgResource code highlighted below to our main menu code. Like earlier, we have comments added for information on each function:

## Main Menu [Begin]
lib.mainMenu = HMENU
lib.mainMenu.entryLevel = 0
lib.mainMenu.wrap = <ul id="menu-area">|</ul>
lib.mainMenu.1 = GMENU
lib.mainMenu.1.useLargestItemY = 1
lib.mainMenu.1 {
NO {
allWrap = <li class="menu-item">|</li>
ATagParams = class="menu-link"
## Add an image resource to load up if available
altImgResource.import = uploads/media/
## Use the media field of the page setup for images
altImgResource.import.field = media
## Import the first image listed in the page setup
altImgResource.import.listNum = 0
## If no images in the page properties, create
## GIFBUILDER image
backColor = #ffffff
XY = [10.w],[10.h]+5
10 = TEXT
10 {
text.field = title
fontFile = fileadmin/templates/deftone.ttf
fontSize = 36
fontColor = #000000
align = left
offset = 0,50
angle = 3
}
}
RO < .NO
RO = 1
RO {
## For rollover, import the second image listed in
## the page properties
altImgResource.import.listNum = 1
10.fontColor = #990000
10.shadow.offset = 1,1
}
ACT < .NO
ACT = 1
ACT {
## For now, the active state will use the same
## altImgResource as the normal state
10.fontColor = #999999
10.shadow.offset = 1,1
}
}
## Main Menu [End]

The new menus will use the resources from the page setup to show items. After we've updated the menu, we'll notice that nothing may have changed initially because we haven't added files to the page resources. This is okay, because it just means that the menu is falling back to GIFBUILDER correctly. To show our images, we can add files to the resources tab of the page properties. Remember, we can access the page properties by right-clicking on our page in the page tree and selecting Edit:

According to our code, the menu should try to load the first image for a normal state, and it will display the second file in the list for when the mouse rolls over it. If we add these resources to our Products page, we will see an image replace the text for that menu item:

On rollover, the Products menu item will show the second image in the list:

As you can see, the altImgResource can be a very helpful and powerful way to use more complex images designed in Photoshop or Illustrator inside our own templates. It even keeps the HTML tags that we wrapped around our menu items and the link tag parameters. If we use altImgResource and an image returns from the page properties, than it will simply override any GIFBUILDER configuration. This is why we can use GIFBUILDER as a seamless backup menu procedure for when an image is not set in the page properties. So, if it's overriding the GIFBUILDER configuration, why is it considered an alternate image resource? I don't know, but according to the TSref "this is how it irreversibly is and has been for a long time."

TYPO3 Templates Create and modify templates with TypoScript and TemplaVoila
Published: November 2010
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on this subject, see here.)

Other types of menus

We have covered the two main types of menus in TYPO3 that we will need to know for template building, TMENU and GMENU. TYPO3 offers other menu options that we do not have time to cover in this article. Because so many of the other menus are extensions of TMENU or GMENU, it was more important that we spend time learning TMENU and GMENU in-depth then try to gloss over all six menu options. Now that we know the big two, we can extend our menus to some of the following options:

  • GMENU_LAYERS and TMENU_LAYERS extend GMENU or TMENU to create a multi-level DHTML (Dynamic HTML) menu.
  • GMENU_FOLDOUT extends GMENU to create a multi-level menu with JavaScript actions.
  • IMGMENU creates a large image map with GIFBUILDER objects.
  • JSMENU creates drop-downs that dynamically load using JavaScript.

In most situations, you won't need to go very deep into any of these menu options that date back to solving problems with Netscape 4 and predate modern JavaScript libraries, but the TSref has detailed information for all of them.

Breadcrumb navigation

Along with standard page tree navigation, TYPO3 menu objects can be used for specific navigation using the special properties. It is possible to list recently updated pages, pages related by keywords, and even a complete directory listing. One of the best options, though, is the rootline menu that shows the path along the rootline from the top of the menu to the current page. In web development, this is called breadcrumb navigation because it leaves a trail for users to take back to the beginning, and it is used in e-commerce sites or websites with deep navigation trees.

To create our own breadcrumb navigation, we need to add a new element to our HTML file and TemplaVoila template. First, we need to add the space for our breadcrumb navigation to our HTML. We can place it directly below the submenu in our HTML file:

<body>
<div id="logo"></div>
<div id="timestamp" style="float: right;"></div>
<ul id="menu-area"><li class="menu-item"><a href="">Menu Item
#1</a></li></ul>
<ul id="submenu-area"><li class="submenu-item"><a
href="">Submenu Item #1</a></li></ul>
<div id="breadcrumb">Top Menu \ Next Page</div>
<div id="banner_image"></div>
<div id="content">This is our content</div>
</body>

Once we've updated our HTML, we need to add a new field to our main TemplaVoila data structure. We will follow the following steps:

  1. Click on TemplaVoila in the far-left menu.
  2. Choose the Storage Folder from the page tree.
  3. Click Update mapping.
  4. Click Modify DS / TO (Data Structure / Template Object) on the mapping page.
  5. At the bottom of the data structure page, add a new field called field_breadcrumb:
  6. Finally, fill in the form for the new field with the following values:
    • Title: Our title can be Breadcrumb Navigation.
    • Mapping Instructions: Just like the original elements, we'll add some basic instructions: Pick the HTML container element where you want the breadcrumb navigation to be placed.
    • Sample Data: Our sample data can be [Breadcrumb navigation goes here].
    • Element Preset: We are going to use TypoScript object to define the menu, so we can go ahead and choose TypoScript Object Path from the drop-down menu.
    • Mapping rules: Like the other elements we've added, we just want some simple rules: div, span, tr, td.
    • Object path: We need a name for our object that will be easy to remember, so we can call it lib.breadcrumb so our editors know exactly what we are creating.
  7. Save the changes to our template and map the new field to the new breadcrumb div tag in our HTML file.

Now that we have updated our TemplaVoila template, we can try out the breadcrumb navigation by defining it at the end of our TypoScript template setup with the following code:

## Declare a new HMENU object
lib.breadcrumb = HMENU
## Define the new object as a rootline
lib.breadcrumb.special = rootline
## Sets the range from the base of the page tree (0) to the
## current level (-1)
lib.breadcrumb.special.range = 0|-1
## Adds basic wrapping and titles to menu
lib.breadcrumb.wrap = Current Location:
lib.breadcrumb.1 = TMENU
lib.breadcrumb.1
{
target
= _top
NO.before
= &nbsp;
NO.after
= &nbsp;/ |*| &nbsp;/ |*| &nbsp;
}

Using this code exactly as it stands (and some CSS like the submenu styling), we can see this output:

Pulling it all together

Now that we've seen the different menu options we can take our pick of what we want to keep for our example site. We've seen the most basic text, text with icons, graphical text, buttons, and designer image resources. Our boss will probably love the graphical main menu, but we might have been experimenting a bit too much when we converted the submenu to little embossed buttons. The alternate images were also great, but stick figures may not be the most helpful navigation aids. So, before we show this off, we can just grab the best bits of our graphical main menu and our text-based submenu:

Summary

In this article we have covered:

  • Create your first graphical menu with a custom font, drop-shadows, and rollover actions
  • Create a breadcrumb navigation menu that helps users see where they are in the website

Further resources on this subject:


About the Author :


Jeremy Greenawalt

Jeremy Greenawalt is a full-time developer and part-time writer with close to ten years professional experience in website and application creation. His first love was writing, but programming quickly followed.He is a co-founder of Vintage 56 where he helps develop websites, online shopping carts, web apps, iPhone/iOS apps, and anything else his friends can think up. Jeremy is also the web director of a large ministry, Generals International. Jeremy lives near Dallas, Texas with his wife, Rebekah, and their ever-youthful puppy, Aingeal. He loves spending time at home reading, playing around on the piano, or just relaxing on the couch with his family. You can read more from Jeremy at pocketrevolutionary.com, and you can follow him on Twitter at @jgreenawalt.

Books From Packt


TYPO3 4.2 E-Commerce
TYPO3 4.2 E-Commerce

TYPO3 4.3 Multimedia Cookbook
TYPO3 4.3 Multimedia Cookbook

Apache OfBiz Cookbook
Apache OfBiz Cookbook

CMS Design Using PHP and jQuery
CMS Design Using PHP and jQuery

Mastering phpMyAdmin 3.3.x for Effective MySQL Management
Mastering phpMyAdmin 3.3.x for Effective MySQL Management

Joomla! 1.5 Top Extensions Cookbook
Joomla! 1.5 Top Extensions Cookbook

Drupal 7
Drupal 7

TYPO3: Enterprise Content Management
TYPO3: Enterprise Content Management


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Y
s
P
V
Q
6
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software