The following tutorial describes the process of creating tabbed navigation in DotNetNuke 3.0. Creating a tabbed look isn't difficult, but there is a slight learning curve if you are new to DotNetNuke skinning.
It is assumed you have a working installation of DotNetNuke 3.0 and Visual Studio 2003 installed and some understanding of HTML and ASP.NET.
There are a few ways to create a skin project for DotNetNuke, but for this tutorial I will be demonstrating the creation of a separate distribution skin project. There are also two flavors of skin creation: ASCX and HTML. For this tutorial I will be demonstrating the HTML approach.
The first step is to create our skin project in Visual Studio 2003. Begin by opening up Visual Studio and creating a new "Empty Project". I have named my project "TabSkin". Following DNN's recommended folder structure, I have set up my project as follows:
Next, we need to create the HTML file that will serve as our skin. To make it easy I copied C:\Projects\DotNetNuke\Portals\_default\Skins\DNN-Blue\Horizontal Menu - Full Width.htm to my local skins folder and renamed it TabSkin.htm since it already has a good basic structure to start from.
After opening TabSkin.htm, you should see something similar to the following in design mode:
Looking at the above layout, you will notice that there are 12 elements contained within the brackets. Each of these bracketed values is known as skin objects. When installed, DotNetNuke converts the HTML skins into ASCX user control skins by replacing each of the skin objects with ASP.NET controls. Our HTML skin is really just a template for creating the final ASCX file. If we examine the HTML source for the [MENU] section, we will see the following:
<TABLE class="skingradient" cellSpacing="0"
cellPadding="3" width="100%" border="0">
<TD width="100%" vAlign="middle" align="left" nowrap>
vAlign="middle" align="right" nowrap>[SEARCH]
The [MENU] skin object is what we will be modifying to produce our tabs. In order to accomplish this, we need to tell the [MENU] skin object how we want it to behave. We do this by specifying attributes for each of the skin objects we wish to modify. These attributes ultimately become attributes of the user control created from the skin object. Because embedding the attributes directly within the HTML would become messy and cumbersome to work with for a visual designer, DotNetNuke facilitates the ability to specify these attributes through an accompanying Skin.xml file.
To specify our attributes, create a new file named "Skin.xml" with the following contents:
The attributes specified within the above listing are as follows:
|use arrows to indicate child submenus.|
|Use arrow images located in the skin rather than those in the /images folder.|
|image used for root level menu breadcrumb arrows.|
|The separator used just after a root level menu item. A use for this might be a right edge of a tab image for example.|
CSS Class used for root menu items.
CSS Class used for root menu items when they are the active tab.
|Menu break |
|Menu root arrow |
<A name=Aboutthe[MENU]SkinObject6>About the [MENU] skin object
While not essential to our tutorial, it may be helpful to understand what output DotNetNuke actually creates when producing the menu. The menu is enclosed within an HTML
<TABLE> element containing a single row with multiple cells. There are two cells for each menu item: one for the actual menu item and one for the menu item separator.
The menu item cell encloses the menu within an additional nested HTML
<TABLE> element. This table contains a single row with two cells. The first cell is for the main menu item elements. This cell contains four possible elements: the root menu item's optional left HTML, the root breadcrumb arrow (if the tab is currently active), the menu title, and the root menu item's optional right HTML. The second cell contains the root menu arrow image which is present if submenus are available.
The following illustrates the layout for a menu containing one menu item:
|Cell 1||Cell 2|
|ROOT MENU LEFT HTML (Optional)||ROOT MENU BREADCRUMB IMAGE (If current tab is active)||ROOT MENU TITLE||ROOT MENU RIGHT HTML (Optional)||
Note: The root menu item's left and right HTML could be used to produce a tab look as well by specifying a left and right image around the title, however for the tab style I am demonstrating it is cleaner to just utilize the menu separator cell. After following this tutorial, you should be adequately equipped to develop more advanced tab images.
Our next step is to provide a style sheet containing the
CSS Class selectors designated within our Skin.xml file. This can be specified globally for the skin package by providing a file named "skin.css". Create this file within your skin folder. Referring back to our attributes there are three class selectors we need to provide.
The first class selector we need to create is
RootMenuItems. This is referenced by both the
RootMenuItemActiveCssClass attributes and is intended to affect the main root menu item cells (refer to Cell 1 of the first gray inner table above). For this tutorial, I have chosen to use the same style for both active and inactive tabs for simplicity. To begin our tab look, we need the top, bottom, and left borders to be visible and the right border left open. This side of the cell will be closed visually with a GIF image. To match the size and color of our image, we also need to make the border color a dark grey, the background color white, and the height 21 pixels. This is accomplished with the following class selector:
border-left: 1px solid #666666;
border-bottom: 1px solid #666666;
border-top: 1px solid #666666;
border-right: 0px solid #666666;
The next class selector we need to create is
MenuBreak. The purpose of this selector is to affect the table containing the root menu item separator which in our case is the cell containing our closing tab image. For our purposes we need to ensure there are no visible borders for this table. This is accomplished with the following class selector:
The final class selector we need to create is
RootArrow. The purpose of this selector is to affect the cell containing the arrow indicator image which appears when the root menu item has submenus available. Since this cell appears between the menu item and the menu separator, this needs to have a top and bottom border but no left or right borders. We also need to ensure that it is of the same height and background color as the other elements. This is accomplished with the following class selector:
border-top: solid 1px #666666;
border-bottom: solid 1px #666666;
The next step will be to create our custom root arrow, root breadcrumb, and right tab images. You can use the images provided in the source download, or create your own and adjust the skin.css styles accordingly. Place these images within your skin folder. You also need to provide a 1x1 pixel transparent GIF image named spacer.gif within your package. You can copy this over from the DotNetNuke images directory. While your skin templates may not directly reference spacer.gif, DotNetNuke uses this image in its final rendering of the menu and may not display correctly in all browsers without it (e.g. Firefox).
The next step is to package up our skins into a zip file. You can do this with any zip utility compatible with the PKZip format. The name of the zip file should be the name of your skin (i.e. "TabSkin.zip"). The documentation that comes with DNN 3.0 for packaging skins seems out of date or incorrect as it suggests that you can just zip up your skins folder. My experience is that the zip file should only contain the contents of the skins folder and not the skins folder itself (which is what you receive following the DNN documentation). If the skins folder itself is contained within the zip file, DNN 3.0 doesn't correctly apply your skin.css. While I have not covered the creation of container skins in this tutorial, there is another format you may use for creating a bundled package containing both portal and container skins. For this format, create your portal skin zip file as before except this time name it skins.zip. Do the same for the container folder naming it containers.zip. Next, zip both of these zip files into a zip with the name of your skin package (i.e. TabSkin.zip). For this step I had to use a different utility, as the built in Windows compressing utility doesn't seem to allow bundling zip files within another zip file due to naming conflicts. When uploaded through DNN this will create a TabSkin folder both under the Containers and Skins folders.
The next step is to upload your skin package. Log into your DNN site as the user host and proceed to the Skins page under the Host menu item. Select the upload Skin link. Next, browse to the location of your packaged zip file and click "Add". Next, click "Upload New File". Clicking the Upload link before clicking the Add will not upload the file. The next screen you should see is a diagnostics screen displaying the results of the upload.
Now that you have created and installed your skin, you can proceed to the Site link under "Common Tasks" and select your TabSkin under the Portal Skin and Admin Skin dropdowns. Click the "Update" link and your skin will be installed. Viola, you now have tabs!
RootMenuItemCssClass class selector to the cell containing the menu item elements. Rather than setting the class of the enclosing
<TR> element which doesn't allow you to affect the borders of the cell. I have included a patched version of the spmenu.js file which corrects the problem. Make a backup of your DotNetNuke\controls\SolpartMenu\spmenu.js file and replace the original with the corrected spmenu.js file. If you aren't using version 3.0.13 of DNN then I can't say what the behavior will be, so you might want to do a diff between my version and the original. I've reported this as a bug to DNN, so perhaps this may be corrected in a future version. After replacing this file, you should see the proper tab images as seen below:
Creating skins and even tabbed menus is pretty easy through DotNetNuke. My thanks to the DNN developers for such a cool product!