Sub-SubMenu for Blogger with Artisteer, part 3 - Dynamic width for the sub-menus
In parts 1 and 2 of this article on the sub-subMenus for Blogger with Artisteer (see "Sub-SubMenu for Blogger with Artisteer, part 1" and « Sub-SubMenu for Blogger with Artisteer, part 2 ») , we have seen how to extend the number of levels of sub menu items for the models ( "templates") created by Artisteer (version 2.3) for Blogger. In this part 3, we will improve the visual appearance of these menus by adjusting their width ( "width ") to the size of the option titles they contain. Note that even if you do not want to use multiple levels of submenus and stay in one, this visual adaptation may still be interesting for you. It may also be for other users Artisteer using other types of template for Blogger, especially pure HTML templates. Such alterations will also itself the subject of a future article in order 'clarify its use.
Without any further waiting, here's the new replacement code for the function artDisplayTopMenu below:
Obviously, this new version of the function artDisplayTopMenu is compatible with the method that we have already seen in Part 2 for replacing the use of the Blogger's "Configure Link List" with a static list of options supplied in the form of JavaScript code. All you have to do to use the other method is to rename the function in the code above from artDisplayTopMenu to artDisplayTopMenu2 and insert the new intermediary function artDisplayTopMenu as it has been described int this Part 2. (Remember that you must also add a bogus argument (dummy) in the dynamic list of Blogger as described in this Part 2.)
If we look more closely at the code provided, we see that this new version of artDisplayTopMenu first includes a call to ComputeWidth:
function artDisplayTopMenu (menuitems)
{
ComputeWidth (menuitems);
...
The role of this function is to (recursively) scan the array menuitems for calculating the required width for each sub-menu and to store at the position [2] of this array this calculated value. This is the width that needs to be written for each link <a href="..."> of each submenu; and it's stored in the format "width: NNpx;" with NN representing the number of pixels required.
Upon the return from this function, the following code will extract this new value for the width that has been calculated and add it to the writing of each HTML link <a href="..."> as a style attribut:
function artDisplayTopMenu (menuitems)
{
...
var sstyle = '';
if (item.length >= 3)
sstyle = item[2];
...
if (itemname.indexOf("=") == 2) {
document.write('<a href="'+itemlink
+'" style="'+sstyle+'">'+itemname.substr(3,itemname.length)+'</a>');
subList = true;
subList2 = true;
subList3 = true;
} else if (itemname.indexOf("+") == 1) {
document.write('<a href="'+itemlink
+'" style="'+sstyle+'">'+itemname.substr(2,itemname.length)+'</a>');
subList = true;
subList2 = true;
} else {
document.write('<a href="'+itemlink
+'" style="'+sstyle+'">'+itemname.substr(1,itemname.length)+'</a>');
subList = true;
}
...
Let us now take a look at this function "ComputeWidth". First, we see that it is divided into two parts: the first initializes some variables and then starts analysing the array "menuitems" for elements that are part of a sub-menu (all other elements are, of course, part of the main menu). When such an item is found - which mean that we are at the beginning of a first level sub-menu -the ComputeWidth2 function is called with the index of this element passed as parameter. This second function will search for all the other elements belonging to the same sub-menu, will determine the greatest width of text needed to display them all and will then enter this value in the array "menuitems" at the position [2] for each element to be part of this same sub-menu.
"ComputeWidth2" is also the function that will call itself recursively for analysing any sub-level menu that will be encoutered while analysing a first level sub-menu. When a sub-menu if finished - with all of its sub-level sub-menus as well - the function return with the index of the next element pass the end of the current sub-menu. The calling function can then resume its analysis of the submenu or of the main menu (if the calling function was ComputeWidth) that it was analysing before encountering a sub-level menu. The whole hierarchy of the main menu with its submenus and their own submenus is in this way recursively analysed.
As this process is done recursively, you can see that it will be very easy to add additional levels if we wish too. This is something that we'll see in a forthcoming article; where we'll take a look at some more advanced functionality to add to our menus.
In order to facilitate its comprehension, I've added some more comments to the code provided for these two functions. Howeer, there are some points that need to be discusssed in much greater details. The first one is the method used to calculate the width in pixels of each option. For this I use the technique seen in the article "Determining string length in pixels [-JavaScript / Ajax / DHTML answers]"; which use an hidden <span> text element into which each piece of text is written and then its exact length in pixels found by retrieving the offsetWidth property of the <span> element.
To use this method, we must first add an element <span> - with an ID equal to "ruler" - to the template and format it exactly the same way as for the submenus' options. For doing this properly, we must not forget to add the styling properties that are beeing inherited and, of course, we are only interested int the properties related to the size of text; excluding other properties like its colors. To be sure that you have the correct formatting, you can also choose to display this <span> element instead of keeping it hidden during the development process. This way, you will quickly notice it if you have made any mistake in its formating.
If this <span> element with an ID of "ruler" is not present in the template or is not found - for example because it has been written later in the HTML code, after the menu section, the function ComputeWidth will create one, format it with a basic style and install it at the beginning of the HTML code (or DOM) of the page. Therefore, it's not strictly necessary for you to create this <span> element but in this case, you should change the basic style used in the function ComputeWidth so that the basic style will fit your needs:
function CompuetWidth (menuitems)
{
...
s.style.visibility = 'hidden';
s.style.fontFamily = "'Times New Roman', Georgia, Times, Serif";
s.style.fontSize = "14px";
s.style.fontWeight = "bold";
s.style.position = "absolute";
s.style.top = 0;
s.style.left = 0;
/* s.style.letterSpacing = "1px"; */
...
(In the code provided at the beginning of this article, two different ways for setting this style are shown and obviously, you can choose which one is better suiting your case.)
To be sure that this element will not change in anything the display of the page, its position is declared as of type "absolute" in the style. This way, its size will have no effect on the display of the HTML elements that follow. Note that even by using a position of type "absolute", this doesn't mean that you can insert this element anywhere in the HTML page. When this code for inserting the element of the menu is executing, there are many <div> elements that have been opened but not closed (these elements will be closed only after the last items of the menu have been written). Inserting a new element at the end of the list at this step means inserting it inside an open <div> element while is it beeing analysed/treated by the browser; something that many won't like. In the case of IE, most likely you<ll get an javascript error or worse, the page won't display at all as the following figure is showing:
The method used in the provided code insert the element by calling "document.body.insertBefore (s, document.body.firstChild)" and is totally safe because this new element will then be inserted at the very beginning of the DOM's hierarchy, therefore making it impossible to be inserted into an open <div> element.
The second point worth to be mentionned here is the margin required around the menu titles. The method used for calculating the exact length in pixels of each title will ignore the calculation of margin requirements; so this is something that we'll have to add. The code in the function ComputeWidth2 () takes this into account by adding a fixed value of 28 pixels, which matches the style of my menus (with margin of 14 pixels per side) but you can obviously adapt this value to your needs:
function ComputeWidth2 (menuitems)
{
...
var swidth = 'width:' + (maxLen + 28) + 'px;';
...
Notice that if you add a proper padding to the style (of formating) of the <span> element; you won't have to correct the value for the margin because the value of this padding will be included into the length in pixel of the text element. However, if you add a margin to the style instead of a padding; its value won't be taken into account for the length in pixel.
You can see the end result of this adjustment function menus on the demo site "Test3 - Sub-SubMenu with Artisteer" :
You can see on this figure that the widths for the sub-menus of level 1, 2 and 3 have all been correctly calculated and if you take a look with either Firefox or IE6, the result is totally correct. However, on IE7 and IE8, there is a big space that appears between the second and third sub-levels (the latter being indicated by the arrow) as it's indicated by the circle in the previous figure.
The display problem with IE7 and IE8 comes from a minor problem in the stylesheet as it is generated by Artisteer and which defines for the left margin of the links <a> elements of the submenus a default value of "auto":
.art-menu ul ul a
{
margin-left: auto;
}
This has the effect of centering more or less the last submenu in its area, as you can see by comparing his position with the position of the previous sub-menu in the figure below, where I have superimposed the two:
The solution is simple: setting the left margin to zero (0) instead of "auto":
.art-menu ul ul a
{
margin-left: 0px;
}
Personally, I have no idea why the value of this margin is to "auto" by default instead of being set to 0. This value of "auto" for the margins is usually used for centering an element on the page but in the case of a sub-menu, I see no reason why this value should be variable and left to the discretion of the browser. Having a margin to be variable is probably one the last thing that you want to see in a sub-menu; especially when there are multiple levels involved.
The final result for our menu is shown on the demo site "Test 3.B - Sub-SubMenu with Artisteer":
You can see on this demo that all the sub-menus are now displaying correctly (red arrow), with a correct width and without any unwanted space between them. This is not only for Firefox and IE6 but for IE7 and IE8 as well. The screenshot above was made with IE7.
This concludes the Part 3 of the article on the sub-menus for Blogger with Artisteer. In Part 4 and 5, we will first see some more advanced techniques to enable us to create (and debug) our menus faster and then in some later parts, we'll take a look on how to add some new exciting features to our menus on Blogger. We will also take a look on how to use these menus with Artisteer templates other than Blogger.
Welcome!
Thanks for your patience!
S. L.
Labels
- Artisteer (5)
- Blogger (6)
- Followers gadget (1)
- Google Friend Connect (1)
- Joomla (1)
- Picasa (1)
- Windows Live Writer (2)
About Me
- Sylvain Lafontaine
- Consultant - Travailleur autonome pour les bases de données et l'internet.
Donate ($CAD)
If you have liked this site or if I've been helpful, you can support my work by making a donation. Thanks.
Disclaimer • Privacy policy
The information on this blog is provided for informational purposes only. The writer is not responsible for any damage caused by performing actions specified on this blog, or by relying on information published on this blog. By using information or components provided on this blog you are accepting these terms.
This blog uses cookies. You can find information about these and about the privacy policy of this blog by clicking here.

2 comments:
great work
Perfect!!!!
Post a Comment